几种线性时间排序
一般我们使用的堆排序,归并排序都是属于比较排序,也就是通过比较元素的大小来进行排序,可以通过决策树分析出比较排序的时间下界是O(nlgn),堆排序和归并排序都是渐进最优的比较排序算法。还有其他的排序方法不是通过比较,下面总结一下:
一:计数排序
大致思路是将数组中所有元素对应小于这个元素的个数存储起来,这样我们可以直接知道这个元素的位置,因为可能出现相同的元素,所以我们从后面输出而且每次找到一个元素的位置后要把对应的小于x的个数减一,这样再次输出时就被会放到前一个位置上。最后的时间很好是O(n),但是要开三个数组,而且其中一个数组要开从0到所有比较的数中最大的数,所以是典型的空间换时间,如果比较的元素中有一些非常大就没有办法进行排序。
#include<iostream>
#include<algorithm>
using namespace std;
const int maxnum = 0xffff;
const int maxsize = 0xff;
int length;
void CounterSort(int a[], int b[], const int k)
{
int c[maxnum];
int i;
for (i = 0; i <= k; i++)
c[i] = 0;
for (i = 1; i <= length; i++)//统计a中不同的数分别出现的个数
c[a[i]]++;
for (i = 1; i <= k; i++) //将c[i]现在代表有几个数小于或等于i
c[i] = c[i] + c[i - 1];
for (i = length; i >= 1; i--)
{
b[c[a[i]]] = a[i];
c[a[i]]--; //对相同元素的个数减一
}
}
int main()
{
int a[maxsize], b[maxsize];
cin >> length;
int max = -1;
for (int i = 1; i <= length; i++)
{
cin >> a[i];
if (max < a[i])
max = a[i];
}
CounterSort(a, b, max);
for (int i = 1; i <= length; i++)
cout << b[i] << " ";
cout << endl;
return 0;
}
二:基数排序&&桶排序
基数排序就是用来排序一些位数相等的数时比较好,基本思路是从低位开始排序,再一位一位往前,总共排序位数d次,能够确保完全拍好序,时间复杂度是O(d(n+k))。感觉跟桶排序是一个意思,可能实现不一样吧,自己写的是感觉基数排序要靠桶排序实现,这两差不多。
#include<iostream>
#include<algorithm>
using namespace std;
const int maxsize = 0xfff;
int n;
void BucketSort(int a[]);
int GetDigit(int num);
void PushNum(int a[], int b[10][maxsize], int digit);
void CollectNum(int a[], int b[10][maxsize]);
int main()
{
int a[maxsize];
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
BucketSort(a);
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
void BucketSort(int a[])
{
int b[10][maxsize] = {0};
int max = -1;
for (int i = 1; i <= n; i++)
if (max < a[i])
max = a[i];
int digit = GetDigit(max);
for (int i = 1; i <= digit; i++)
{
PushNum(a, b, i);
CollectNum(a, b);
if (i != digit)
memset(b, 0, sizeof(b));
}
}
int GetDigit(int num)//求所有数中位数最高的位数
{
int digit = 0;
while (num)
{
digit++;
num /= 10;
}
return digit;
}
void PushNum(int a[], int b[10][maxsize], int digit)
{
int div = 1;
for (int i = 1; i <= digit; i++)
div *= 10;
for (int i = 1; i <= n; i++)
{
int num = (a[i] % div - a[i] % (div / 10)) / (div / 10);//得到相应的第div/10位上的数
int count = ++b[num][0];//用b[num][0]存储对应的数有几个元素
b[num][count] = a[i];
}
}
void CollectNum(int a[], int b[10][maxsize])
{
int k = 0;
for (int i = 0; i < 10; i++)
for (int j = 1; j <= b[i][0]; j++)
a[++k] = b[i][j];
}