【算法】桶排序(Bucket Sort)详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1. 概述

桶排序Bucket Sort又称箱排序是一种比较常用的排序算法。其算法原理是将数组分到有限数量的桶里再对每个桶分别排好序可以是递归使用桶排序也可以是使用其他排序算法将每个桶分别排好序最后一次将每个桶中排好序的数输出。

2. 算法详解

桶排序的思想就是把待排序的数尽量均匀地放到各个桶中再对各个桶进行局部的排序最后再按序将各个桶中的数输出即可得到排好序的数。

  1. 首先确定桶的个数。因为桶排序最好是将数据均匀地分散在各个桶中那么桶的个数最好是应该根据数据的分散情况来确定。首先找出所有数据中的最大值mx和最小值mn

    根据mx和mn确定每个桶所装的数据的范围 size有
    size = (mx - mn) / n + 1n为数据的个数需要保证至少有一个桶故而需要加个1

    求得了size即知道了每个桶所装数据的范围还需要计算出所需的桶的个数cnt有
    cnt = (mx - mn) / size + 1需要保证每个桶至少要能装1个数故而需要加个1

  2. 求得了sizecnt后即可知第一个桶装的数据范围为 [mn, mn + size)第二个桶为 [mn + size, mn + 2 * size)…以此类推
    因此步骤2中需要再扫描一遍数组将待排序的各个数放进对应的桶中。

  3. 对各个桶中的数据进行排序可以使用其他的排序算法排序例如快速排序也可以递归使用桶排序进行排序

  4. 将各个桶中排好序的数据依次输出最后得到的数据即为最终有序。

例子
例如待排序的数为3, 6, 9, 1

1求得 mx = 9mn = 1n = 4
size = 9 - 1) / n + 1 = 3
cnt = (mx - mn) / size + 1 = 3

2由上面的步骤可知共3个桶每个桶能放3个数第一个桶数的范围为 [1, 4)第二个[4, 7)第三个[7, 10)
扫描一遍待排序的数将各个数放到其对应的桶中放完后如下图所示

3对各个桶中的数进行排序得到如下图所示

4依次输出各个排好序的桶中的数据即为1, 3, 6, 9
可见最终得到了有序的排列。


3. 测试

JAVA

import java.util.ArrayList;

/**
 * @author yumu
 * @date 2022/8/25
 */
public class BucketSort {

    public void bucketSort(int[] nums) {
        int n = nums.length;
        int mn = nums[0], mx = nums[0];
        // 找出数组中的最大最小值
        for (int i = 1; i < n; i++) {
            mn = Math.min(mn, nums[i]);
            mx = Math.max(mx, nums[i]);
        }
        int size = (mx - mn) / n + 1; // 每个桶存储数的范围大小使得数尽量均匀地分布在各个桶中保证最少存储一个
        int cnt = (mx - mn) / size + 1; // 桶的个数保证桶的个数至少为1
        List<Integer>[] buckets = new List[cnt]; // 声明cnt个桶
        for (int i = 0; i < cnt; i++) {
            buckets[i] = new ArrayList<>();
        }
        // 扫描一遍数组将数放进桶里
        for (int i = 0; i < n; i++) {
            int idx = (nums[i] - mn) / size;
            buckets[idx].add(nums[i]);
        }
        // 对各个桶中的数进行排序这里用库函数快速排序
        for (int i = 0; i < cnt; i++) {
            buckets[i].sort(null); // 默认是按从小打到排序
        }
        // 依次将各个桶中的数据放入返回数组中
        int index = 0;
        for (int i = 0; i < cnt; i++) {
            for (int j = 0; j < buckets[i].size(); j++) {
                nums[index++] = buckets[i].get(j);
            }
        }
    }

    public static void main(String[] args) {
        int[] nums = {19, 27, 35, 43, 31, 22, 54, 66, 78};
        BucketSort bucketSort = new BucketSort();
        bucketSort.bucketSort(nums);
        for (int num: nums) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

C++

#include <iostream>
#include <vector>

using namespace std;

class BucketSort {
public:
    void bucketSort(vector<int> &nums) {
        int n = nums.size();
        int mn = nums[0], mx = nums[0];
        for (int i = 1; i < n; i++) {
            mn = min(mn, nums[i]);
            mx = max(mx, nums[i]);
        }
        int size = (mx - mn) / n + 1;   // size 至少要为1
        int cnt = (mx - mn) / size + 1; // 桶的个数至少要为1
        vector<vector<int>> buckets(cnt);
        for (int i = 0; i < n; i++) {
            int idx = (nums[i] - mn) / size;
            buckets[idx].push_back(nums[i]);
        }
        for (int i = 0; i < cnt; i++) {
            sort(buckets[i].begin(), buckets[i].end());
        }
        int index = 0;
        for (int i = 0; i < cnt; i++) {
            for (int j = 0; j < buckets[i].size(); j++) {
                nums[index++] = buckets[i][j];
            }
        }
    }
};


int main() {
    vector<int> nums = {19, 27, 35, 43, 31, 22, 54, 66, 78};
    BucketSort().bucketSort(nums);
    for (auto num: nums) {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}

4. 时间复杂度和空间复杂度分析

最好时间复杂度 : O(n + k)
其中k为桶的个数。即当数据是均匀分散排列的那么每个桶分到的数据个数都是一样的这个步骤需要O(k)的书剑复杂度在对每个桶进行排序的时候最好情况下是数据都已经是有序的了那么最好的排序算法的时间复杂度会是O(n)因此总的时间复杂度是 O(n + k)

最坏时间复杂度O(n^2)
当对每个桶中的数据进行排序的时候所使用的排序算法最坏情况下是O(n^2)因此总的最坏情况下的时间复杂度为O(n^2。

平均时间复杂度O(n + n²/k + k) <=> O(n)
如果k是根据Θ(n)来获取的那么平均时间复杂度就是 O(n)。


5. 参考文献

[1] https://iq.opengenus.org/time-and-space-complexity-of-bucket-sort/
[2] https://www.programiz.com/dsa/bucket-sort

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
返回列表

上一篇:CEEMDAN算法及其应用

下一篇:sdl