比较排序算法时间复杂度下界为O(nlogn),这里介绍一种非比较排序算法:计数排序,其时间复杂度为O(n)。
计数排序原理
假定有三个数组,A,B,C,A为待排序数组,B为输出数组,C为临时数组。
计数排序的思想是对于A中每一个元素x确定小于等于x元素个数n,将其保存到临时数组C中,这样通过查找临时数组C可以直接确定待排序数组各元素位置,从而避免比较。
假定数组A保存如下数据
3 | 1 | 3 | 5 | 4 | 0 |
可以确定有1个数小于等于0,2个数小于等于1,4个数小于等于3,5个数小于等于4,6个数小于等于5由此得到数组C
1 | 2 | 4 | 5 | 6 |
这样显然0应该摆在0号位置,1摆在1号位置,第一个3摆在3号位置后C[3]递减,第二个3摆在2号位置,依次类推,最终完成排序。
参考代码:
#include <iostream>
#include <string>
using namespace std;
int Counter_Sort(int *input,int *output,int length,int type);
void main()
{
int i;
int a[]={9,8,7,6,5,4,3,2,1,22,67,11,5,3,99,102,54};
int b[17];
if (Counter_Sort(a,b,17,0) == 0)
{
for (i=0;i<17;i++)
{
cout <<b[i]<<" ";
}
cout << endl;
}
else
{
cout <<"排序错误"<<endl;
}
}
int Counter_Sort(int *input,int *output,int length,int type)
{
int i;
int tmp[1024];
if (length > 1024)
{
return -1;
}
for (i=0;i<1024;i++)
{
tmp[i]=0;
}
for (i=0;i<length;i++)
{
if (input[i]<1024)
{
tmp[input[i]]++;
}
else
{
return -2;
}
}
for (i=1;i<1024;i++)
{
tmp[i]=tmp[i]+tmp[i-1]; //计算<=s中某元素的变量个数
}
for (i=0;i<length;i++) //改为for (i=length-1;i>=0;i--)排序就是稳定的
{
if (0 == type) //正序
{
output[tmp[input[i]]-1]=input[i];
tmp[input[i]]--;
}
else if (1 == type) //逆序
{
output[length-tmp[input[i]]]=input[i];
tmp[input[i]]--;
}
else
{
return -3;
}
}
return 0;
}
在确定tmp[s[i]]元素个数时消耗O(n)时间,确定小于某元素个数消耗O(n)时间,确定元素最终位置消耗O(n)时间,总算法时间复杂度为O(n),需要辅助空间为max(s[i]),即O(n)
关于计数排序是否是稳定的:前文给出的计数排序代码不是稳定的,假设有3,3,3,前文的代码会将第一个3放到最后一个3的位置。
稍微修改一下循环变量可使计数排序变稳定,将代码的第53行改为:
for (i=length-1;i>=0;i--)
修改后是从后面赋值,第3个3肯定还是放到第3个3位置。