计数排序、基数排序、桶排序 非比较排序算法,平均时间复杂度都是O(N).
这些排序元素,因为其关键值本身就含有了定位特征,因而不需要比较就可以确定其前后位置。
1、计数排序是一种简单的排序方法,将排序结果放到另一个的新的数组中。
计数排序要求 待排序的元素的关键值是位于0-k之间的正整数。因而是个非常特殊的情况。
输入数组A:元素关键值是 0-K的正整数,可以有重复值
输出数组B:输出数组A的一个非减序列
中间数组C:大小K,它的i(0<=i<=k)索引位置存储的是A元素集合和。
这里意思是:原始数组A元素变成了中间数组C下标。
?void Sort(int array[],int n,int outArray[],int k) //默认 区间是0——K
{
int* Temp=new int[k+1];
memset(Temp,0,(k+1)*sizeof(int));
for(int i=0;i<n;i++)
Temp[array[i]]++;
int m=0;
for (int i=0;i<=k;i++)
{
while(Temp[i]-->0)//如果有重复的话要递减
outArray[m++]=i; //array[m++]也是可以的 这里是标准计数排序的优化 可以使outArray 省去
}
delete[] Temp;
}
第一次我以为这就是计数排序,但后来发现 这个算法虽然可以解决有限区间的排序问题。但不是标准的(算法导论上)计数排序。
这个算法严格的来说并非排序算法,像统计(引用别人的描述)。所以也就不是什么稳定排序与非稳定排序,因为排序后的数组中的数已尽被全新的数替代。 已尽改变以前的数组中元素。
引用:维基百科计数排序
当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。
由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。
算法的步骤如下:
找出待排序的数组中最大和最小的元素
统计数组中每个值为i的元素出现的次数,存入数组C的第i项
对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
void BookSort(int array[],int outarray[],int n,int k)
{
//标准排序
int* Temp=new int[k+1];
memset(Temp,0,(k+1)*sizeof(int));
for(int i=0;i<n;i++)
Temp[array[i]]++;
for (int i=1;i<=k;++i)
{
Temp[i]=Temp[i]+Temp[i-1];
}
//for (int i=n-1;i>=0;--i) //从后往前遍历原始数组 是稳定排序
for (int i=0;i<n;++i) //从前往后遍历原始数组 就不再是稳定排序
{
//计数排序核心思想
int m=array[i];//原始数组元素关键字的值
int q=Temp[m];//根据原始数组元素关键字的值 对应于临时数组的下标 找到临时数组的值
outarray[ q- 1] = array[i];//临时数组的值 即是原始数组原始关键字的 排序位置
Temp[m] =Temp[m]-1;//因为有重复的数 排序的位置需要减去一个
}
}
代码测试:
int N=20;
int array[]={0,0,8,9,6,9,4,0,6,0,0,5,65,76,77,8,79,98,89,96};
int* outArray=new int[N];
Sort(array,N,outArray,100);
//BookSort(array,outArray,N,100);
for (int i=0;i<N;++i)
{
cout<<outArray[i]<<" ";
}
system("PAUSE");
return EXIT_SUCCESS;