1. 计数排序
思想:对于有限个一定范围内的整数,我们可以采用遍历的方式得出每一个数的个数,放入相应的值所对应的下标数组的位置中,再通过将原数组从后往前遍历,并对照与 计数数组之间的关系,将原数组数据排好序放入新的数组中。一般情况下k<=len,代码如下:
void CountSort(int arr[],int ret[],int k,int len ) //k代表原数组中不重复的数的个数,即将相同数值的数记为1,有多少个不同的数
{
int *c=(int *)malloc(sizeof(int)*(k)); //申请空间以计数
memset(c,0,sizeof(int)*(k)); //将计数数组每一个元素初值初始化为0
for(int i=1,i<=len;++i) //循环遍历原数组,遍历完成之后,数组c中存放的各个数值对应的个数,如c[5]=2表示原数组中5的个数有2个
{
c[arr[i]]++;
}
for(i=2;i<=k;++i)
{
c[i]+=c[i-1]; //数组c记录小于等于原数组值的个数有几个
}
for(int j=len;j>0;j--)
{
ret[c[arr[j]]]=arr[j]; //最终ret数组中c[arr[j]]的位置就存放原数组中的该值
c[arr[j]]--; //一个数已经排好序,则相应计数位置应少1
}
}
计数排序的最大时间复杂度为O(k+n),并且为稳定排序。
2.基数排序
思想:基数排序主要针对一个数的位数进行排序,如各个待排序数的个位,十位,百位进行排序,先对个位进行排序,再依据个位排序,对十位进行排序,进行局部位置调整,调整完成之后再依据相对有序的当前排序数进行百位排序,假设每个数最多只有三位的话,通过百位排序并进行调整之后,就有序了。代码如下:
RADIX-SORT( A , d ) 1 for i ← 1 to d 2 do use a stable sort to sort array A on digit i |
int brr[len]={0};
void RadisSort(int arr[],int ret[],int len,int d)//d表示最大的数的位数有几位
{
for(int i=1,i<=d;++i)
{
for(int j=1;j<=len;++j)
{
brr[j]=arr[j]/pow(10,i-1)%10; //取得各位数值的相应的个位,十位百位等的数值
}
CountSort(arr,brr,ret[],k,len ); //调用稳定的计数排序进行当前位置的数值排序,这里不能完全套用上面的计数排序,但思路相同。
arr=ret;
}
}
3.桶排序
思想:桶排序将均匀分布的随机的固定区间的小数等份划分之后,通过将这些小数经过哈希函数散列到各个桶中,则前一个桶中的数据肯定小于后一个桶中的数据,对于桶的个数,我们想划分为几个区间,就是几个桶,也即数组的长度,对于桶中的数据,我们可以采用链表的形式将其数据有序插入到相应桶中,这里的链表是针对单个桶内的元素而言,因为我们并不知道一个桶中到底会有多少元素。伪代码描述如下: