十大简单排序:计数排序

tech2023-02-03  109

计数排序

思想:用一个例子来说明计数排序的思想,对N个50-59之间的整数进行排序,N可能很大。虽然数据量很大,但是取值范围却很小,我们可以利用一个数组a[10],a[0].....a[9]对应50....59,也就是说,数据减去50作为数组的下标,例如56,那么对应的下标就是56-50=6,那么a[6]执行一次加1操作,代表出现了56这个数,对数组中的所有元素都是一个道理,最终a[0]的数值就是原数组中50的个数,同理a[1]...a[9]。最后遍历a[10]数组,输出相应的值即可。代码如下。

int *sort(int arr[],int len) { int *result = new int[len]; int a[10] = {0}; for(int i=0;i<len;i++) { a[arr[i]-50]++; } for(int i=0,j=0;i<10;i++) { while(a[i]-- > 0) result[j++] = i+50; } return result; }

可以仔细的想一想,计数排序不是一种比较的排序,且最终的结果无法表现其稳定性。很难说是稳定的。那么怎么改进,可以确保排序后的顺序是稳定的呢?我们称上述的a[10]数组为统计数组。可以改进统计数组,将统计数组的每一项改进成前一项加本项,表示的含义是统计数组的元素值代表的是在原数组中比其对应值小或等于的个数,这话有点绕,仔细想下。举个例子。

原数组:        0  1  3   2   3   4   4   5

原统计数组: 1  1  1   2   2   1  分别代表0、1、2、3、4、5出现的个数

改进的统计数组: 1   2   3   5    7   8  分别代表小于等于0、1、2、3、4、5的个数

最后倒序遍历原数组,第一个是5,那么改进后统计数组下标为5-0的位置处的值,就代表5在排序后的数组中的位置,也即  8.(是第8个位置,下标为7,写代码时要注意)

第二个被遍历到的是4,那么改进后统计数组下标为4-0位置的值,代表4在排序后数组中的位置,即 7,注意,此时要将改进后统计数组下标为4处的值减1,这样当遍历到第二个4的时候,其在排序后数组中的位置就变为了6。这样就保证了两个4在原数组中的位置和在排序后数组中的相对位置是一样的。从而是稳定的,接下来的两个3同理。

代码如下:

//通用解法 int *sort(int arr[],int len) { if(len == 0) return NULL; //先计算出最小值和最大值,从而可以确定统计数组的大小 int min = arr[0]; int max = arr[0]; for(int i=1;i<len;i++) { if(min > arr[i]) { min = arr[i]; } if(max < arr[i]) { max = arr[i]; } } int *result = new int[len]; int *helpArr = new int[max-min+1]; //求解统计数组 for(int i=0;i<len;i++) { helpArr[arr[i]-min]++; } //改进统计数组 for(int i=1;i<max-min+1;i++) { helpArr[i] = helpArr[i] + helpArr[i-1]; } //倒序遍历原数组 for(int i=len-1;i>=0;--i) { //排序后数组中的位置,注意此处要减1 int pos = helpArr[arr[i]-min]-1; //将原数组中的值放入新数组中 result[pos] = arr[i]; //将改进后统计数组中的相应位置值减1 helpArr[arr[i]-min]--; } return result; }

最后的分析:

1)计数排序是非比较的排序算法

2)适用于数据量大但是取值范围小的情况

3)可以稳定

4)是这一种以牺牲空间复杂度换取时间复杂度的算法

最新回复(0)