算法:排序之桶排序和基数排序

Posted 我们全都爱学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法:排序之桶排序和基数排序相关的知识,希望对你有一定的参考价值。

把这两个算法放在一起,因为感觉这两个排序算法的通用性比较小,必须针对具体问题做具体的算法分析设计才能使用。


桶排序:


桶排序假设输入的待排序元素的值可以落在一个值区间内;于是:

  1. 遍历待排序数组,按照一定规则,把所有n个元素分布到m个桶中。

    1. 每一个桶代表一个区间范围,所以桶和桶之间是排序的。

  2. 然后对每一个桶执行桶内排序;桶内排序可以使用任意排序算法。

  3. 最后把所有的桶的元素拼接起来返回即可。


举一个例子:


例如要对n个大小为[1..1000]范围整数进行排序,我们设定桶的大小是10,那么我们需要m=100个桶:

  1. 把1-10的元素分配到1号桶

  2. 把10-20的元素分配到2号桶

  3. 把20-30的元素分配到3号桶

  4. ...

  5. 把990-1000的元素分配到100号桶

分配完之后,针对每一个桶进行桶内排序,任意排序算法,例如快速,插入等等都行。

最后把所有的桶的元素都拼接起来得到排序后输出;因为桶之间是按区间排序的,桶内元素也已经排序好了,所以这一步只要拼接起来就行了。


另外如果我们有1000个桶,那么每个桶最多只有一个元素,这样首次分配完之后,筒内的元素已经是排行好的了(因为只有最多一个元素),就不需要再进行桶内元素的排序,直接执行桶间的拼接输出就行。


桶排序的时间复杂度是接近O(n),但是另外需要辅助空间O(n)。


算法实现:

  // get the maximun value from array

int max(int a[], int n) {

    int max= a[0];

    for(int i = 1; i < n; i++) {

        if(a[i] > max) {

            max= a[i];

        }

    }

    return max;

}


void sort_bucket(int a[] , int n) {

    int bucketlen = max(a, n) + 1;

    int bucket[bucketlen] = { 0 };


    for (int i = 0; i < n; i++) {

        bucket[a[i]]++;    // in case there are duplicated elements

    }


    int j = 0;

    for (int i = 0; i < bucketlen; i++) {

        while (bucket[i] != 0) {

            a[j++] = i;    // put element back to array

            bucket[i]--;

        }

    }

}


基数排序:


基数排序(以整形为例),把整数以10进制按每位拆分,然后从最低位到最高位依次比较各个位排序,主要分为两个过程:

  1. 分配:先从个位开始,根据位值(0-9)分别放到0~9号桶。

    1. 例如13, 个位为3,则放入3号桶中。

  2. 收集:再将放置在0~9号桶中的数据按顺序放到数组中。

  3. 重复上述1和2的过程,取更高一位,直到最高位排好序为止。


用一个例子说明就比较清楚:

假设待排序数组为:73  22  93  43  55  14  28  65  39  81。

  1. 第一步分配,按个位

    • 0号桶:

    • 1号桶:81

    • 2号桶:22

    • 3号桶:73,93,43

    • 4号桶:14

    • 5号桶:55,65

    • 6号桶:

    • 7号桶:

    • 8号桶:28

    • 9号桶:39

  2. 第一次收集

    • 81 22 73 93 43 14 55 65 28 39

  3. 第二次分配,注意这次按照十位数分配

    • 0号桶:

    • 1号桶:15

    • 2号桶:22,28

    • 3号桶:39

    • 4号桶:43

    • 5号桶:55

    • 6号桶:65

    • 7号桶:73

    • 8号桶:81

    • 9号桶:93

  4. 第二次收集

    • 14  22  28  39  43  55  65  73  81  93


我们观察到此时已经排序完成了。


算法实现:

// get the numer in position(start from 1, right to left)

// for example

// numinpos(7463, 1) = 3

// numinpos(7463, 2) = 6

// numinpos(7463, 3) = 4

// numinpos(7463, 4) = 7

int numinpos(int num,int pos) {

    int temp = 1;

    for (int i = 0; i < pos - 1; i++) {

        temp *= 10;

    }


    return (num / temp) % 10;

}


void sort_radix(int a[], int n)

{

    // allocate space

    int *radixarrays[10];

    for (int i = 0; i < 10; i++) {

        radixarrays[i] = (int *)malloc(sizeof(int) * (n+ 1));

        radixarrays[i][0] = 0;  // index=0 is used to record elements number

    }


    // we define pos from 1 to 10, because the max int  value does

    // not exceed 11 numbers.

    // (gdb) p/u 0x7fffffff    (int)

    // $1 =  2147483647

    // (gdb) p/u 0xffffffff    (unsigned int)

    // $2 = 4294967295

    for (int pos = 1; pos <= 10; pos++) {

        for (int i = 0; i < n; i++) { // allocate stage

            int num = numinpos(a[i], pos);

            int index = ++radixarrays[num][0];

            radixarrays[num][index] = a[i];

        }


        int j = 0;

        for (int i = 0; i < 10; i++) {    // collect  stage

            for (int k = 1; k <= radixarrays[i][0]; k++) {

                a[j++] = radixarrays[i][k];

            }

            radixarrays[i][0] = 0;

        }

    }


    // free space

    for (int i = 0; i < 10; i++) {

        free(radixarrays[i]);

    }

}


所以总体感觉这两个排序算法有一定的关联性,而且通用性都不高,需要对具体待排序元素的性质做分析,才能更好的应用这两个排序算法。


以上是关于算法:排序之桶排序和基数排序的主要内容,如果未能解决你的问题,请参考以下文章

数据结构和算法(十七)排序算法之基数排序

排序算法 (11.基数排序)

算法计数排序桶排序和基数排序详解

基数排序的算法思想及性能分析

基数排序算法的Java实现

算法渣-排序-基数排序