Welcome

首页 / 软件开发 / 数据结构与算法 / 内部排序:计数排序、基数排序和桶排序

内部排序:计数排序、基数排序和桶排序2014-12-06前言

最后三种排序算法了,由于都不是基于比较的排序,因此这三种排序算法可以以线性时间运行。但是因为限制条件的特殊性,因此应用面没有基于元素比较的排序算法广,但是在很多特定的情况下还是蛮有用途的,而且效率极高。

计数排序

计数排序是建立在这样的前提条件下的:假设n个输入元素的每一个都是0到k区间内的一个整数,其中k为某个整数。因此我们后面所写的程序也只是针对0到k之间的元素进行排序,换句话说,排序元素中不能有负数。

计数排序的基本思想是:对一个输入元素x,先确定所有输入元素中小于x的元素个数,那么排序后x所在的位置也就明确了。比如,所有的输入元素中有10个元素小于x,那么排好序后x的位置序号就应该是11。当然,如果有相同元素,自然要放到相邻的位置上。

算法导论上给出了计数排序的很详细的伪代码,我们根据此伪代码,并设数组arr为输入数组,arr中的每个元素值在0到k之间,brr为排序后的输出数组,crr记录arr中每个元素出现的次数。写出代码如下:

/* 第一种形式实现计数排序 计数排序后的顺序为从小到大 arr[0...len-1]为待排数组,每个元素均是0-k中的一个值 brr[0...len-1]为排序后的输出数组 crr[0...k]保存0...k中每个值在数组arr中出现的次数 */void Count_Sort(int *arr,int *brr,int *crr,int len,int k){int i,j=0;//数组crr各元素置0for(i=0;i<=k;i++)crr[i] = 0;//统计数组arr中每个元素重复出现的个数for(i=0;i<len;i++)crr[arr[i]]++;//求数组arr中小于等于i的元素个数for(i=1;i<=k;i++)crr[i] += crr[i-1];//把arr中的元素放在brr中对应的位置上for(i=len-1;i>=0;i--){brr[crr[arr[i]]-1] = arr[i];//如果有相同的元素,则放在下一个位置上crr[arr[i]]--;}}
很明显上面代码的时间复杂度为O(n+k),但用到了brr来保存排序结果,我们可以它做些改进,使排序原地进行,如下:

/* 第二种形式实现计数排序 计数排序后的顺序为从小到大 arr[0...len-1]为待排数组,每个元素均是0-k中的一个值 crr[0...k]保存0...k中每个值在数组arr中出现的次数 */void Count_Sort(int *arr,int *crr,int len,int k){int i,j=0;//数组crr各元素置0for(i=0;i<=k;i++)crr[i] = 0;//统计数组arr中每个元素重复出现的个数for(i=0;i<len;i++)crr[arr[i]]++;//根据crr[i]的大小,将元素i放入arr适当的位置for(i=0;i<=k;i++)while((crr[i]--)>0){arr[j++] = i;}}
采用如下代码测试:

int main(){int i; //待排序数组,每个元素均在0-8之间int arr[] = {2,1,3,8,6,0};int brr[6];int crr[9];Count_Sort(arr,brr,crr,6,8);printf("计数排序后的结果为:");for(i=0;i<6;i++)printf("%d ",brr[i]);printf("
");return 0;}
测试结果如下: