桶排序(bucket sort)之基数排序

简单理解

桶排序是通过使用不同的桶容器来容纳序列中的数,然后再按桶的顺序进行收集,以实现有序的序列。而基数排序则是使用十个桶容器将一个待排序的序列排序。其中十个桶的大小是可以根据需要进行改变的,分别代表0-9十个数字,用来容纳每一趟排序中的相应位置上的数。

核心算法思想描述

以序列97、3、100、77从小到大排序为例。

1、对序列中的每个值,根据值的个位的数字,将其放到相应的桶中。例如,97放在数字'7'这个桶中,3放在数字'3'这个桶中,100放在数字'0'这个桶中,77放在数字'7'这个桶中。这个过程被称为“分布过程”。

分布后各桶的数据如图:

0 1 2 3 4 5 6 7 8 9
100 null 3 null null null null 97 null null
null null null null null null null 77 null null
2、对各个桶进行遍历,并把其中的数字按照从桶'0'到桶'9'的顺序依次取出收集到序列中。这个过程被称为“收集过程”。
收集后序列如下:100、3、97、77,可见个位数已经有序。

3、随后对十位和百位依次重复这两个过程,过程示意如下:

对十位分布:

0 1 2 3 4 5 6 7 8 9
100 null null null null null 77 null null 97
3 null null null null null null null null null
对十位收集:100、3、77、97。

对百位分布:

0 1 2 3 4 5 6 7 8 9
3 100 null null null null null null null null
77 null null null null null null null null null
97 null null null null null null null null null
对百位收集:3、77、97、100。

算法性能分析

  • 空间效率:一趟排序需要的辅助存储空间为r(r个容器),但以后的排序中重复使用这些容器,所以基数排序的空间复杂度为\(O(r)\)
  • 时间效率:基数排序需要进行d趟分配和收集,一趟分配需要\(O(n)\),一趟收集需要\(O(r)\),所以基数排序的时间复杂度为\(O(d(n + r))\),它与序列的初始状态无关。
  • 稳定性:基数排序能够保持相对顺序,是稳定的。

C++实现

考虑到桶排序中各个桶的大小是不确定的,在每一趟排序的过程中大小可能产生变化,故我们使用vector实现各个桶,并用array将十个由vector实现的桶整合在一起。

#include <iostream>
#include <vector>
#include <array>
using namespace std;

void bucketSort(int a[], int n) {
    array<vector<int>, 10> buckets;

    // 确定最大数的位数,最多的位数决定需要进行多少趟桶排序
    int max = a[0];
    for (int i = 0; i < n; ++i)
        if (max < a[i])
            max = a[i];
    int times = 0;
    while (max) {
        ++times;
        max /= 10;
    }

    // 进行桶排序
    int div = 10;
    for (int time = 0; time < times; ++time) {
        // 数字分散于桶中
        for (int i = 0; i < n; ++i)
            buckets[a[i] % div / (div / 10)].push_back(a[i]);   // 取相应位置上的数字

        // 收集桶中的数据并清空桶
        int cnt = 0;
        for (int i = 0; i < 10; ++i) {
            for (size_t j = 0; j < buckets[i].size(); ++j)
                a[cnt++] = buckets[i][j];
            buckets[i].clear();
        }
        div *= 10;
    }
}

int main() {
    const int SIZE = 20;
    int a[SIZE] = { 0 };
    for (int i = 0; i < SIZE; ++i) {
        a[i] = rand() % 1000;
        cout << a[i] << " ";
    }
    cout << "\n\n";

    bucketSort(a, SIZE);

    for (auto elem : a)
        cout << elem << " ";

    return 0;
}
posted @ 2020-04-14 22:30  southernEast  阅读(267)  评论(0编辑  收藏  举报