桶排序和计数排序

突然想自己写个桶排序,然后做课后题又发现了计数排序,觉得挺有趣的。不过书上都没有给代码,所以就自己写了一下代码,超级烂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)。

时间: 2024-08-10 15:00:03

桶排序和计数排序的相关文章

基于非比较的排序:计数排序(countSort),桶排序(bucketSort),基数排序(radixSort)

计数排序 条件:要排序的数组的元素必须是在一定范围的,比如是1~100.在排序之前我们必须知道数组元素的范围. 思路:顾名思义:就是用一个数组来计数的. 步骤: 1.用一个数组来计数count[ ],将要排序的数组arr[ ]的元素记为数组count[ ]数组的下标,如果数组arr[]中有两个数相同就在count[]++.如count[arr[i]]++. 2. 再一次遍历数组count[ ],将count[i]  +=  count[i-1]+count[i-2]+....+count[0],

线性排序之基数排序,桶排序,计数排序

基数排序 计数排序 桶排序 基数排序,桶排序,计数排序是三种线性排序方法,突破了比较排序的O(nlogn)的限制.但是只适用于特定的情况. 基数排序 以下为维基百科的描述: 基数排序 : 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次排序.这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列. 基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digit

基于非比較的排序:计数排序(countSort),桶排序(bucketSort),基数排序(radixSort)

计数排序 条件:要排序的数组的元素必须是在一定范围的,比方是1~100.在排序之前我们必须知道数组元素的范围. 思路:顾名思义:就是用一个数组来计数的. 步骤: 1.用一个数组来计数count[ ],将要排序的数组arr[ ]的元素记为数组count[ ]数组的下标,假设数组arr[]中有两个数同样就在count[]++.如count[arr[i]]++. 2. 再一次遍历数组count[ ],将count[i]  +=  count[i-1]+count[i-2]+....+count[0],

排序算法(七)非比较排序:计数排序、基数排序、桶排序

前面讲的是比较排序算法,主要有冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等. 非比较排序算法:计数排序,基数排序,桶排序.在一定条件下,它们的时间复杂度可以达到O(n). 一,计数排序(Counting Sort) (1)算法简介 计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数.然后根据数组C来将A中的元素排到正确的位置.它只能对整数进行排序. (2)算法描述和实现 得到待排序数的范围(在

排序算法下——桶排序、计数排序和基数排序

桶排序.计数排序和基数排序这三种算法的时间复杂度都为 $O(n)$,因此,它们也被叫作线性排序(Linear Sort).之所以能做到线性,是因为这三个算法是非基于比较的排序算法,都不涉及元素之间的比较操作. 1. 桶排序(Bucket Sort)? 1.1. 桶排序原理 桶排序,顾名思义,要用到"桶".核心思想是将要排序的数据分到几个有序的桶里,每个桶的数据再单独进行排序.桶内排完序后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了. 1.2. 桶排序的时间复杂度分析 如

算法学习-02(希尔排序,计数排序,桶排序,基数排序)

希尔排序 # 希尔排序 # 希尔排序是对插入排序的升级改造 # 它的大致流程是 # 1.将长度为n的序列 分为d = n//2组 # 2.使每一组变的有序 # 3.将序列分为 d1 = d // 2 组 # 4.将每一组变的有序 # 5.直到最后 d 小于等于 0 def inster_sort_gap(li,gap): for i in range(gap,len(li)): tmp = li[i] j = i - gap while j >= 0 and tmp > li[j]: li[j

经典排序算法 - 计数排序Counting sort

经典排序算法 - 计数排序Counting sort 注意与基数排序区分,这是两个不同的排序 计数排序的过程类似小学选班干部的过程,如某某人10票,作者9票,那某某人是班长,作者是副班长 大体分两部分,第一部分是拉选票和投票,第二部分是根据你的票数入桶 看下具体的过程,一共需要三个数组,分别是待排数组,票箱数组,和桶数组 var unsorted = new int[] { 6, 2, 4, 1, 5, 9 };  //待排数组 var ballot = new int[unsorted.Len

基数排序与桶排序,计数排序【详解】

桶排序简单入门篇^-^ 在我们生活的这个世界中到处都是被排序过的东东.站队的时候会按照身高排序,考试的名次需要按照分数排序,网上购物的时候会按照价格排序,电子邮箱中的邮件按照时间排序……总之很多东东都需要排序,可以说排序是无处不在.现在我们举个具体的例子来介绍一下排序算法. 首先出场的是我们的主人公小哼,上面这个可爱的娃就是啦.期末考试完了老师要将同学们的分数按照从高到低排序.小哼的班上只有5个同学,这5个同学分别考了5分.3分.5分.2分和8分,哎,考得真是惨不忍睹(满分是10分).接下来将分

桶排序,计数排序算法

计数排序: 桶排序:www.roading.org/algorithm/introductiontoalgorithm 算法模型: 1,桶排序假设待排的一组数统一分布在一个范围[m....n],将这一范围划分为几个子范围,也就是桶bucket. 例如,如何将0---999范围的数,划分到10个桶中?范围中数的个数用K表示,那么K/10=1000/10=100,就是每个桶装100个元素,即[0..99]装到第一个桶中,[100..199]装到第二个桶中,...以此类推. 怎么判断一个数组该放到哪个