• 桶排序和计数排序


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

  • 相关阅读:
    链表的逆置(无聊而写)
    C
    大型分布式站点的技术需求
    leetcode第一刷_Best Time to Buy and Sell Stock
    微商行业面临洗礼,微盟萌店是否能完毕“神补刀”?
    oracle函数 CONCAT(c1,c2)
    oracle函数 CHR(n1)
    oracle函数 ASCII(x1)
    oracle函数 INTERVAL c1 set1
    oracle函数 SESSIONTIMEZONE
  • 原文地址:https://www.cnblogs.com/lustar/p/7308089.html
Copyright © 2020-2023  润新知