桶排序和计数排序
Posted luStar
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了桶排序和计数排序相关的知识,希望对你有一定的参考价值。
突然想自己写个桶排序,然后做课后题又发现了计数排序,觉得挺有趣的。不过书上都没有给代码,所以就自己写了一下代码,超级烂0 0下面先简单介绍下这两种排序
桶排序
桶排序,就是根据散列的思想进行数据的排序。假设有M个桶,采用最简单的hash(key)=key,这样无需比较,就可以把数存入相应的桶中。针对冲突排解问题,此时查找链的方式显然不再适用,采用独立链法,把每个桶以链表的形式存储雷同元素,定义相同元素的偏序,这样能实现排序的稳定性。桶排序完全采用了简单的哈希策略,是比较容易理解的。同时,完全摒弃了CBA式的方式,从而可以突破复杂度O(nlogn)的界限。通过空间换时间的策略,可以达到O(n)的时间复杂度,代价是O(M+N)的额外空间。下面是对于整型数组的桶排序,代码很烂我也没有改,已经测试过:
1 struct node 2 { 3 node(int v = 0, node* s = NULL) :value(v), succ(s) {} 4 int value; 5 node* succ; 6 }; 7 void insert(node &a, int b)//b插入到a后面 8 { 9 node* t = new node(b); 10 if (a.succ) t->succ = a.succ; 11 a.succ = t; 12 } 13 node* bucketSort(int* A, int n, int k)//数的范围为[0,k) 14 { 15 node* bucket = new node[k](); 16 for (int i = 0; i < n; i++) 17 insert(bucket[A[i]],A[i]); 18 return bucket; 19 } 20 void show(node a) 21 { 22 while (a.succ) 23 { 24 a = *(a.succ);//第一个节点作为哨兵不输出 25 cout << a.value << " "; 26 } 27 } 28 int main() 29 { 30 int A[15] = { 2,0,1,3,3,0,1,9,7,7,15,11,13,12,10}; 31 node* p = bucketSort(A, 15, 16); 32 for (int i = 0; i < 16; i++) 33 show(p[i]); 34 system("pause"); 35 return 0; 36 }
下面有测试例子,已经经过了测试,不过这里仅把排序的结果存入了一个申请空间的列表然后输出,没有进行释放的操作,也没有存入原数组或者另外一个数组0 0看具体的要求可以改动
计数排序
计数排序的基本策略,基于这样的事实:一个有序序列,元素m的秩,应当等于序列中全部元素中,小于等于m的元素数量。所以计数排序算法可以归纳如下:遍历序列,对于每个元素,再遍历整个序列,用一个额外的数组进行计数。不难看出,时间复杂度为O(n^2)。显然,无法接受这样的复杂度。
可以考虑用散列的方法来降低复杂度。同样,对于[0,k)的元素,选取M个桶,假设元素数量为n,先遍历序列,用桶数组进行计数。随后,每一个后面的桶的计数=前面桶的数量+它自身的计数。这样,每个桶的数字-1就等于桶对应元素的秩。同时,也可以处理相同元素的问题,因为当元素存在其他因素的偏序时,数字也加在了桶数组的计数中,桶数组只需要从后向前输出,就可以维持这种偏序。实现代码如下:
1 /*计数排序*/ 2 int* countSort(int* A,int k,int n)//[0,k)范围内n个数 3 { 4 int* tmp = new int[k]; 5 int* s = new int[n]; 6 memset(tmp, 0, sizeof(int) * k); 7 for (int i = 0; i < n; i++)//原始数组中的计数 8 tmp[A[i]]++; 9 for (int i = 0; i < k - 1; i++)//记录不大于该数的数字个数 10 tmp[i + 1] += tmp[i]; 11 for (int i = n - 1; i >= 0; i--)//逆序输出 12 s[--tmp[A[i]]] = A[i];//计数哈希数组-1即为应当对应的秩,用原数组的数赋值 13 delete[] tmp; 14 return s; 15 }
代码已经经过了测试。可以看到,只需要两趟原数组遍历,一趟桶数组遍历即可完成,时间复杂度为O(M+n)。同样,辅助空间为桶数组,空间复杂度为O(M)。不难看出,计数排序适用的最合适情况,是M远小于n的时候,即数据较多而范围确不大。此时,时间复杂度仅为O(n)。
以上是关于桶排序和计数排序的主要内容,如果未能解决你的问题,请参考以下文章