動畫:一篇文章快速學會桶排序

內容介紹

桶排序簡介

前面學過計數排序,計數排序是一個非基於比較的排序算法,它的優點在於在對必定範圍內的整數排序時,它的複雜度爲Ο(n+k)。java

所謂桶就是存放多個數據的容器,桶排序也是非基於比較的排序算法,將待排序數據按照必定的規則存放到對應的桶中,再進行排序與合併。桶排序能夠對必定範圍內的數據包括小數進行排序。桶排序能夠突破基於比較排序算法的時間複雜度O(nlogn)。算法

桶排序的思想

將待排序數據分配到有限數量的桶裏。每一個桶再單獨進行子排序,最後按順序將多個桶中的數據進行合併,排序完成。當待排序的數組內的數值是均勻分配的時候,桶排序的時間複雜度爲O(n)。編程

桶排序動畫演示

假設有10我的給某個商品進行評分,評分的範圍是0~1之間的小數,例如{0.6, 0.85, 0.9, 0.5, 0.35, 0.2, 0.1, 0.85, 0.8, 0.5} 這10個數據。通常沒有特殊要求排序算法都是升序排序,小的在前,大的在後,效果以下: 數組

桶排序分析

經過上面動畫能夠看出桶排序分爲4個步驟:微信

  1. 劃分合適數量的桶。
  2. 將全部待排序數據放入到對應的桶中。
  3. 使用合理的算法對每一個非空桶進行子排序。
  4. 按順序將每一個桶中數據進行合併。

第一步:劃分合適數量的桶動畫

關於如何劃分合適數量的桶,根據不一樣規模和不一樣範圍的數據,咱們採起不一樣的劃分方式。目前數據都是0到1之間小數,數據比較均勻,咱們等分紅4個桶,每一個桶的範圍都是0.25,效果以下: 3d

第二步:將全部待排序數據放入到對應的桶中code

遍歷待排序數據,將每一個數據放入對應範圍的桶中,效果以下: blog

第三步:使用合理的算法對每一個非空桶進行子排序排序

待排序數據劃分到不一樣桶中後,每一個桶中的數據仍是無序的,以下圖所示: 從上圖能夠看到,第二個桶不用排序,其餘桶須要進行排序,分別對每一個桶中的數據再使用合適的排序算法,好比快速排序。排序後效果以下圖:

第四步:4.按順序將每一個桶中數據進行合併

合併前效果以下圖: 如今範圍小的桶在前面,範圍大的桶在後面,而且每一個桶中的數據也是從小到大排序的,所以咱們只須要從左往右將每一個桶中的數據取出放到數組中便可。取出第一個桶後的數據以下: 取出第二個桶後的數據以下:

取出第三個桶後的數據以下:

取出第四個桶後的數據以下:

當全部桶中的數據都取出後排序就完成了。

桶排序代碼編寫

public class BucketSort {
    public static void main(String[] args) {
        double[] arr = {0.6, 0.85, 0.9, 0.5, 0.35, 0.2, 0.1, 0.85, 0.8, 0.5};

        bucketSort(arr);

        System.out.println("排序後: " + Arrays.toString(arr));
    }

    public static void bucketSort(double[] arr) {
        // 獲取最大值和最小值
        double max = arr[0];
        double min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            double num = arr[i];
            if (num > max)
                max = num;
            else if (num < min)
                min = num;
        }

        // 桶的數量
        int bucketNumber = 4;

        // 每一個桶的範圍
        double range = (max - min) / bucketNumber;

        // 1.初始化全部桶,每一個桶都是LinkedList,方便增長數據
        LinkedList<Double>[] buckets = new LinkedList[bucketNumber];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new LinkedList<>();
        }

        // 2.將全部待排序數據放入到對應的桶中
        for (int i = 0; i < arr.length; i++) {
            double num = arr[i];
            int index = (int) ((num - min) / range);
            if (index == bucketNumber)
                index -= 1; // 若是這個數字正好是最大值,計算出索引就是number,會數組越界,放到最後一個桶中
            buckets[index].add(num);
        }

        // 3.使用合理的算法對每一個非空桶進行子排序
        for (int i = 0; i < buckets.length; i++) {
            // 對每一個桶中的數據進行排序
            Collections.sort(buckets[i]);
        }

        // 4.按順序將每一個桶中數據進行合併
        int index = 0;
        for (int i = 0; i < buckets.length; i++) {
            LinkedList<Double> bucket = buckets[i];
            for (int j = 0; j < bucket.size(); j++) {
                arr[index] = bucket.get(j);
                index++;
            }
        }
    }
}

桶排序的侷限性

若是數據通過桶的劃分以後,有些桶裏的數據很是多,有些很是少,很不平均,那桶內數據排序的時間複雜度就不是常量級了。在極端狀況下,若是數據都被劃分到一個桶裏,桶排序就退化爲O(nlogn)的排序算法,以下圖所示: 桶排序對待排序數據的要求是很是苛刻的,適用場景是在數據分佈相對比較均勻或者數據跨度範圍並非很大時。若是數據跨度很是大,空間消耗就會很大。因此桶排序不多使用。

桶排序比較適合用在外部排序中

所謂的外部排序就是數據存儲在外部磁盤中、數據量比較大、內存有限,沒法將數據所有加載到內存中。好比說咱們有50GB的訂單數據,咱們但願按訂單金額進行排序,可是咱們的內存有限只有幾GB,沒辦法一次性把50GB的數據都加載到內存中。假設訂單金額最小是0.1元,最大是10萬元。能夠將全部訂單根據金額劃分到100個桶裏,第一個桶存儲金額在0.1元到100元以內的訂單,第二桶存儲金額在101元到200元以內的訂單,依次類推。每個桶對應一個文件。訂單金額在0.1元到10萬元之間並不必定是均勻分佈的,因此50GB訂單數據是沒法均勻地被劃分到100個文件中的。有可能某個金額區間的數據特別多,劃分以後對應的文件很大,無法一次性讀入內存,針對某些劃分以後仍是比較大的文件,咱們能夠繼續劃分,好比訂單金額在0.1元到100元之間的比較多,咱們就將這個區間繼續劃分爲10個小區間,0.1元到10元,11元到20元,21元到30元依次類推,而後將每一個桶對應的數據讀取到內存中使用快速排序進行排序,結果保存在文件中,最後合併到已排序的文件中。

桶排序的複雜度

  1. 空間複雜度:數據規模爲n,劃分到k個桶中,總空間複雜度O(n + k)
  2. 時間複雜度:1.獲取最大值和最小值,遍歷數組,操做次數爲n。2.初始化全部桶,操做次數爲k。3.將全部待排序數據放入到對應的桶中操做次數爲n。4.每一個非空桶進行子排序使用時間複雜度爲O(nlogn)的快速排序總操做次數爲(k/n)*log(k/n)*k。5.按順序將每一個桶中數據進行合併操做次數n。因此總的時間複雜度爲:3n+k+(k/n)*log(k/n)*k,所以時間複雜度爲:O(n+k+logn-logk)
  3. 穩定性:穩定

總結

桶排序也是非基於比較的排序算法,將待排序數據按照必定的規則存放到對應的桶中,再進行排序與合併。桶排序能夠對必定範圍內的數據包括小數進行排序。桶排序能夠突破基於比較排序算法的時間複雜度O(nlogn)。

桶排序的思想:將待排序數據分配到有限數量的桶裏。每一個桶再單獨進行子排序,最後按順序將多個桶中的數據進行合併,排序完成。當要被排序的數組內的數值是均勻分配的時候,桶排序的時間複雜度爲O(n)。

桶排序對待排序數據的要求是很是苛刻的,適用場景是在數據分佈相對比較均勻或者數據跨度範圍並非很大時。若是數據跨度很是大,空間消耗就會很大,若是數據都被劃分到一個桶裏,桶排序就退化爲O(nlogn)的排序算法,因此桶排序不多使用。

桶排序比較適合用在外部排序中。


原創文章和動畫製做真心不易,您的點贊就是最大的支持! 想了解更多文章請關注微信公衆號:表哥動畫學編程

相關文章
相關標籤/搜索