基數(shù)排序就這么簡單

一、基數(shù)排序(桶排序)介紹

來源360百科:

基數(shù)排序(radix sort)屬于"分配式排序"(distribution sort),又稱"桶子法"(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些"桶"中,藉以達到排序的作用,基數(shù)排序法是屬于穩(wěn)定性的排序,其時間復(fù)雜度為O (nlog(r)m),其中r為所采取的基數(shù),而m為堆數(shù),在某些時候,基數(shù)排序法的效率高于其它的穩(wěn)定性排序法。

從上面的簡單介紹,是并不了解基數(shù)排序是怎么弄的~基數(shù)排序不同與其他的7種排序,其他7種排序本質(zhì)上都是按照交換或者比較來進行排序,但是基數(shù)排序并不是,它是按照分配,回收(分配到不同的位置上,然后回收)..不斷分配..回收來進行排序,直到有序..

聽上去好像很高大上,很難的樣子,其實不然?;鶖?shù)排序挺簡單的,下面我就來看一下基數(shù)排序的流程....

我們有9個桶,將數(shù)組的數(shù)字按照數(shù)值分配桶中:

image

ps:圖片來源于網(wǎng)絡(luò),侵刪

上面我們發(fā)現(xiàn):如果將桶按順序進行回收,那么我們的排序就完成了~

可是,一般我們的數(shù)組元素都不僅僅是個位數(shù)的數(shù)字的呀,那么高位數(shù)的數(shù)字又怎么弄呢??比如:23,44,511,6234這些高位數(shù)..

其實也是一樣的:

  • 第一趟桶排序將數(shù)字的個位數(shù)分配到桶子里面去,然后回收起來,此時數(shù)組元素的所有個位數(shù)都已經(jīng)排好順序了
  • 第二趟桶排序?qū)?shù)字的十位數(shù)分別分配到桶子里面去,然后回收起來,此時數(shù)組元素的所有個位數(shù)和十位數(shù)都已經(jīng)排好順序了(如果沒有十位數(shù)、則補0)
  • 第三趟桶排序?qū)?shù)字的百位數(shù)分別分配到桶子里面去,然后回收起來,此時數(shù)組元素的所有個位數(shù)和十位數(shù)和百位數(shù)都已經(jīng)排好順序了(如果沒有百位數(shù)、則補0)
  • ..................................
  • 直至全部數(shù)(個、十、百、千位...)排好順序,那么這個數(shù)組就是有序的了。
image

ps:圖片來源于網(wǎng)絡(luò),侵刪

機智的同學可能就會發(fā)現(xiàn)了,關(guān)于這個桶我們可以用二維數(shù)組來進行存放。

10個桶子就是10列,如果分配時有的數(shù)字相同的話,那么就弄成多行~

二、基數(shù)排序體驗

首先我們有以下這個數(shù)組:


   int[] arrays = {6,  4322, 432, 344, 55 };

現(xiàn)在我們有10個桶子,每個桶子下能裝載arrays.length個數(shù)字..


int[][] buckets = new int[arrays.length][10];

效果如下:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| | | | | | | | | | |
| | | | | | | | | | |
| | | | | | | | | | |
| | | | | | | | | | |
| | | | | | | | | | |

2.1第一趟分配與回收

將數(shù)組的每個個位數(shù)進行分配到不同的桶子上:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| | | | | | | 6 | | | |
| | | 4322 | | | | | | | |
| | | 432 | | | | | | | |
| | | | | 344 | | | | | |
| | | | | | 55 | | | | |

分配完之后,我們按照順序來進行回收:得到的結(jié)果應(yīng)該是這樣子的:{4322,432,344,55,6}

2.2第二趟分配與回收

將數(shù)組的每個十位數(shù)進行分配到不同的桶子上(像6這樣的數(shù),往前邊補0):

于是我們可以得到這樣的排序:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 6 | | | | | | | | | |
| | | 4322 | | | | | | | |
| | | | 432 | | | | | | |
| | | | | 344 | | | | | |
| | | | | | 55 | | | | |

分配完之后,我們按照順序來進行回收:得到的結(jié)果應(yīng)該是這樣子的:{6,4322,432,344,55}

2.3第三趟分配與回收

將數(shù)組的每個百位數(shù)進行分配到不同的桶子上(像6、55這樣的數(shù),往前邊補0):

于是我們可以得到這樣的排序:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 6 | | | | | | | | | |
| 55 | | | 4322 | | | | | | |
| | | | | 432 | | | | | |
| | | | 344 | | | | | | |
| | | | | | | | | | |

分配完之后,我們按照順序來進行回收:得到的結(jié)果應(yīng)該是這樣子的:{6,55,4322,344,432}

2.3第四趟分配與回收

將數(shù)組的每個百位數(shù)進行分配到不同的桶子上(像6、55,344,432這樣的數(shù),往前邊補0):

于是我們可以得到這樣的排序:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 6 | | | | | | | | | |
| 55 | | | | | | | | | |
| 344 | | | | | | | | | |
| 432 | | | | | | | | | |
| | | | | 4322 | | | | | |

分配完之后,我們按照順序來進行回收:得到的結(jié)果應(yīng)該是這樣子的:{6,55,344,432,4322}

此時我們的數(shù)組就已經(jīng)可以排好序了~~~過程就是這樣子,其實不難就只有兩個步驟:

  • 將數(shù)組的每一位放進桶子里
  • 回收
  • 循環(huán)......

三、基數(shù)排序代碼編寫

我們的基數(shù)排序是按照個、十、百、千位...來進行存放的。前面的演示是已經(jīng)知道數(shù)組元素的數(shù)據(jù)的情況下來進行存放,但是一般我們是不去理會數(shù)組內(nèi)元素的值的。那如果位數(shù)很多(萬位)或者都是個位數(shù),這個條件我們怎么去處理呢?

我們可以這樣做:先求出數(shù)組最大的值,然后不斷/10,只要它能大于0,那么它的位數(shù)還有~

3.1求出數(shù)組最大的值

這個我在前面寫遞歸的時候就有這個代碼了,我就直接搬去遞歸的代碼過來了,順便復(fù)習一哈吧:

  • 當然了,更好的是直接用for循環(huán)來找出來就行了(易讀性好一些)

    /**
     * 遞歸,找出數(shù)組最大的值
     * @param arrays 數(shù)組
     * @param L      左邊界,第一個數(shù)
     * @param R      右邊界,數(shù)組的長度
     * @return
     */

    public static int findMax(int[] arrays, int L, int R) {

        //如果該數(shù)組只有一個數(shù),那么最大的就是該數(shù)組第一個值了
        if (L == R) {
            return arrays[L];
        } else {

            int a = arrays[L];
            int b = findMax(arrays, L + 1, R);//找出整體的最大值

            if (a > b) {
                return a;
            } else {
                return b;
            }
        }

3.2代碼實現(xiàn)


    public static void radixSort(int[] arrays) {

        int max = findMax(arrays, 0, arrays.length - 1);

        //需要遍歷的次數(shù)由數(shù)組最大值的位數(shù)來決定
        for (int i = 1; max / i > 0; i = i * 10) {

            int[][] buckets = new int[arrays.length][10];

            //獲取每一位數(shù)字(個、十、百、千位...分配到桶子里)
            for (int j = 0; j < arrays.length; j++) {

                int num = (arrays[j] / i) % 10;

                //將其放入桶子里
                buckets[j][num] = arrays[j];
            }

            //回收桶子里的元素
            int k = 0;

            //有10個桶子
            for (int j = 0; j < 10; j++) {
                //對每個桶子里的元素進行回收
                for (int l = 0; l < arrays.length ; l++) {

                    //如果桶子里面有元素就回收(數(shù)據(jù)初始化會為0)
                    if (buckets[l][j] != 0) {
                        arrays[k++] = buckets[l][j];

                    }

                }

            }

        }
    }

搞了一堆數(shù)測試了一哈:

image

四、總結(jié)

基數(shù)排序(桶排序)要理解起來并不困難,不過值得注意的是:基數(shù)排序?qū)τ胸摂?shù)和0的數(shù)列難以進行排序

  • 因此,往往有0和負數(shù)的數(shù)組一般我們都不用基數(shù)來進行排序

基數(shù)排序的要點就兩個:

  • 分配:按照元素的大小來放入不同的桶子里
  • 回收:將桶子里的元素按桶子順序重新放到數(shù)組中
  • 重復(fù).....兩個步驟

參考資料:

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學,可以關(guān)注微信公眾號:Java3y

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部的...
    Luc_閱讀 2,372評論 0 35
  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    閑云清煙閱讀 820評論 0 6
  • 排序 符號:Θ 插入排序 選擇排序 堆排序 歸并排序 冒泡排序 快速排序 桶排序 基數(shù)排序 計數(shù)排序 插入排序 插...
    liuyanhongwl閱讀 496評論 0 2
  • 忙里偷閑發(fā)條簡書??赐炅恕读柩础?。沒有看完其他(三本。)親愛的三毛是書信集,不合胃口。獵巫人進展一般。近代史…費腦...
    葉開開閱讀 262評論 0 0
  • 今天關(guān)鍵詞:練習 學的知識越多,越發(fā)現(xiàn)任何的一些小小的成就,都需要不斷的練習。比如任何語言方面、技能方面的點滴成績...
    營養(yǎng)私教西西閱讀 315評論 0 0

友情鏈接更多精彩內(nèi)容