動畫:什麼是基數排序?

2021-03-02 景禹

基數排序

與基於比較的排序算法(歸併排序、堆排序、快速排序、冒泡排序、插入排序等等)相比,基於比較的排序算法的時間複雜度最好也就是

計數排序(Counting Sort)的時間複雜度為

那麼問題來了,當這個元素的的範圍在 1 到

此時就不能用計數排序了奧,因為這種情況下,計數排序的時間複雜度達到了

比如對數組 [170, 45, 75, 90, 802, 24, 2, 66] 這個而言,數組總共包含 8 個元素,而數組中的最大值和最小值之差為 802 - 2 = 800 ,這種情況下,計數排序就 」失靈了「 。

那麼有沒有那種排序算法可以在線性時間對這個數組進行排序呢?

答案就是今天要講的 基數排序(Radix Sorting) 。基數排序的總體思想就是從待排序數組當中,元素的最低有效位到最高有效位 逐位 進行比較排序;此外,基數排序使用計數排序作為一個排序的子過程。

下面我們就以數組  [170, 45, 75, 90, 802, 24, 2, 66] ,快樂學習基數排序!

數組當中的最大值 802 為三位數,所以我們在不足三位的數字前面補 0 ,即[170, 045, 075, 090, 802, 024, 002, 066]方便後續說明基數排序。

第一步:按數組當中元素的最低有效位,個位 [170 ,045 ,075 , 090 ,802 , 024 , 002 , 066 ],進行計數排序:

第二步:按數組當中元素的次最低有效位,十位數  [170, 090, 802, 002, 024, 045, 075, 066] ,進行計數排序:

第三步:按數組當中元素的最高有效位,百位  [802, 002, 024, 045, 066, 170, 075, 090] ,進行計數排序:

這樣我們就完成了基數排序,得到了一個有序數組 [2, 24, 45, 66, 75, 90, 170, 802] .

高清視頻動畫實現代碼
import java.io.*; 
import java.util.*; 
  
class Radix { 
  
    // 獲取數組中的最大值 
    static int getMax(int arr[], int n) 
    { 
        int max = arr[0]; 
        for (int i = 1; i < n; i++) 
            if (arr[i] > mx) 
                max = arr[i]; 
        return max; 
    } 
  
    // 計數排序
    static void countSort(int arr[], int n, int exp) 
    { 
        int output[] = new int[n]; //輸出數組 
        int i; 
        int count[] = new int[10]; 
        Arrays.fill(count,0); 
  
        // 統計數組中元素第 exp 位的數目
        for (i = 0; i < n; i++){
            count[(arr[i]/exp)%10]++; 
        }
  
        // 對 count[] 數組進行轉
        for (i = 1; i < 10; i++){
            count[i] += count[i - 1]; 
        }
  
        // 進行計數排序 
        for (i = n - 1; i >= 0; i--) 
        { 
            output[count[ (arr[i]/exp)%10 ] - 1] = arr[i]; 
            count[ (arr[i]/exp)%10 ]--; 
        } 
  
        // 輸出到數組arr[]中
        for (i = 0; i < n; i++){ 
            arr[i] = output[i]; 
        }
    } 
  
    // 基數排序
    static void radixsort(int arr[], int n) 
    { 
        // Find the maximum number to know number of digits 
        int m = getMax(arr, n); 
  
        // 對數組當中的數字按照每一個有效位進行一趟計數排序。 
        for (int exp = 1; m/exp > 0; exp *= 10){
            countSort(arr, n, exp);         
        } 
    } 
  
    // 進行輸出
    static void print(int arr[], int n) 
    { 
        for (int i=0; i<n; i++) 
            System.out.print(arr[i]+" "); 
    } 
  
  
    /*Driver function to check for above function*/
    public static void main (String[] args) 
    { 
        int arr[] = {170, 45, 75, 90, 802, 24, 2, 66}; 
        int n = arr.length; 
        radixsort(arr, n); 
        print(arr, n); 
    } 

實現當中有一個細節需要解釋一下,那就是如何從最低位到最高位取每一個數字的該位的值。答案很簡單了,就是除 10 取餘。

比如 802 ,要取最低位,802 % 10 = 2 ,就取到了個位;緊接著除 10 取商數 802 / 10 = 80 ,然後對商數 80 進行除 10 取餘數,就可以得到十位了,80 % 10 = 0 ;最後再對 8010 取商數 80 / 10 = 8 , 然後對商數 8 進行除  10 取餘數,8 % 10 = 8 就可以得到百位數。

代碼中的 (arr[i] / exp) % 10 就可以輕鬆理解啦,  exp 就相當於控制位數,而取餘操作就相當於取出第  exp 位的值。

當然徹底搞懂基數排序,前提是你要清楚計數排序(Counting Sort),又到打廣告的時間了,推薦看一下 漫畫:什麼是計數排序?。

複雜度分析 時間複雜度

則基數排序整個時間複雜度為

對於一個較大的數

假設

那麼基數排序的時間複雜度就為

可是當我們將這個

也就說,當數字用

對於元素的跨度(範圍)比較大的數組而言,基數排序的運行時間可能比快速排序要好。但是對於基數排序而言,其漸近時間複雜度中隱含了更高的常量因子,並非完全的線性;而快速排序更有效地利用硬體緩存,提高其效率。此外,基數排序使用計數排序作為子過程,計數排序佔用額外的空間來對數組進行排序。

但是基數排序解決我們最開始所提出的問題,當數據範圍在 1  到  

空間複雜度

計數排序使用了額外的空間進行排序,空間複雜度為

推薦閱讀:

圖解「歸併排序」算法(修訂版)

圖解:什麼是快速排序?

漫畫:什麼是計數排序?

作者:景禹,一個追求極致的共享主義者,想帶你一起擁有更美好的生活,化作你的一把傘。

相關焦點

  • 動畫 | 什麼是基數排序?
    基數排序和計數排序一樣無需進行比較和交換,和桶排序一樣利用分布和收集兩種基本操作進行排序。基數排序是把每一個元素拆成多個關鍵字,一個關鍵字可以在每一個元素上同等的位置進行計數排序,一個元素拆成多個關鍵字可以看作是要進行幾輪分桶,以一個元素最長的長度為準。 基數排序可以看成多(單)關鍵字的排序,可以想像成桶排序那樣分桶排序,也可以像計數排序那樣歸約化分治。 基數排序的思想是將待排序序列中的每組關鍵字進行桶排序。
  • 什麼是基數排序?
    但是還是有少數的排序算法沒寫,下面的一篇就是。這篇文章用漫畫的形式講解了基數排序,通俗易懂。什麼是計數排序呢?讓我們舉例說明一下。計數排序有什麼局限呢?像這樣把字符串元素按位拆分,每一位進行一次計數排序的算法,就是基數排序(Radix Sort)。
  • 基數排序
    號內回複數據結構,獲取整套算法視頻本文作者:靜默虛空歡迎點擊下方閱讀原文要點基數排序與本系列前面講解的七種排序方法都不同它是根據關鍵字中各位的值,通過對排序的N個元素進行若干趟「分配」與「收集」來實現排序的。 不妨通過一個具體的實例來展示一下,基數排序是如何進行的。 設有一個初始序列為: R {50, 123, 543, 187, 49, 30, 0, 2, 11, 100}。我們知道,任何一個阿拉伯數,它的各個位數上的基數都是以0~9來表示的。
  • Python實現基數排序
    基數排序將數據按位進行分桶,然後將桶中的數據合併。每次分桶只關注其中一位數據,其他位的數據不管,最大的數據有多少位,就進行多少次分桶和合併。基數排序除了用於對整數進行排序,也可以用於對浮點數、字符串進行排序。基數排序可以分為最高位優先法和最低位優先法,兩種方法的結果相同。最高位優先(Most Significant Digit first)法,簡稱MSD法。
  • 排序算法---基數排序,動圖詳解,Java實現!
    基數排序「基本思想:」將所有待比較數值統一為同樣的數位長度,數位較短的數前面補零。從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列。int[] bucketElementCounts = new int[10]; //桶中元素個數在此,我們還可以發現一個問題就是可能會存在空桶佔用空間資源,所以基數排序典型的佔用空間換取時間,文章末尾會對這種排序時間和空間複雜度的分析!
  • ...選擇,插入,希爾,歸併,快排,堆排序,計數排序,桶排序,基數排序)
    無論是什麼數據進去,時間複雜度都是O(n*2)。數據規模越小越好,唯一的好處就是不佔用額外的空間。思路:在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。然後再從剩餘未排序的數組匯總繼續尋找最小(大)元素,依次類推。
  • 動畫 | 什麼是堆排序?
    所以堆排序分為兩個階段,構造堆有序和下沉排序階段。 構造堆有序階段是將原始數據重新組織安排到一個二叉堆中,堆有序就是一棵二叉樹的每個節點都優先於它的兩個子節點,不代表數組有序; 下沉排序階段是將二叉堆中取出優先級高的直至取出所有元素,得到數組有序結果。
  • 基數排序算法詳解(C語言代碼實現)
    基數排序不同於之前所介紹的各類排序,前邊介紹到的排序方法或多或少的是通過使用比較和移動記錄來實現排序,而基數排序的實現不需要進行對關鍵字的比較,
  • 動畫:面試官問我插入排序和冒泡排序哪個更牛逼?
    排序對於每個開發者來講,都多多少少知道幾個經典的排序算法,比如我們之前以動畫形式分享的冒泡排序,也包括今天要分享的插入排序。還有一些其他經典的排序,小鹿整理的共有十種是面試常問到的,冒泡排序、插入排序、希爾排序、選擇排序、歸併排序、快速排序、堆排序、桶排序、計數排序、基數排序。雖然我們基本知道了這些排序算法,但是在實際項目開發以及面試中往往出乎我們所料。
  • 看動畫學算法之:排序-冒泡排序
    簡介排序可能是所有的算法中最最基礎和最最常用的了。排序是一個非常經典的問題,它以一定的順序對一個數組(或一個列表)中的項進行重新排序。排序算法有很多種,每個都有其自身的優點和局限性。今天我們來學習最最簡單的冒泡排序算法。冒泡排序的原理冒泡排序的原理很簡單,我們想像一下一個一個的氣泡上浮的過程。
  • Excel如何排序?8個動畫告訴你排序的用法
    Excel表格有時候為了方便,會對表格內容進行分類排序,今天給大家分享表格中排序的應用,8個動畫教學,輕鬆對Excel表格進行排序。1、數值大小排序這是排序最普遍的一種操作,將數字從大到小排序,或者是從小到大排序。點擊開始-編輯-排序和降序,選中降序(升序)就可以了。
  • 面試官問我插入排序和冒泡排序哪個更牛逼?
    ,比如我們之前以動畫形式分享的冒泡排序,也包括今天要分享的插入排序。還有一些其他經典的排序,小鹿整理的共有十種是面試常問到的,冒泡排序、插入排序、希爾排序、選擇排序、歸併排序、快速排序、堆排序、桶排序、計數排序、基數排序。雖然我們基本知道了這些排序算法,但是在實際項目開發以及面試中往往出乎我們所料。在面試中,經常會被問到各種排序之間的比較;在實際項目中,往往排序的數據不是我們所練習的整數。
  • 排序算法問題:穩定排序與不穩定排序
    (給算法愛好者加星標,修煉編程內功)作者:紫紅的淚https://www.cnblogs.com/codingmylife/archive/2012/10/21/2732980.html前言排序算法的穩定與不穩定究竟是指的什麼
  • 十大排序算法,來這看看-基本思想+動畫演示+C語言實現
    以此類推,直到全部待排序的數據元素的個數為零。動畫動畫  for (i = 0; i < 5; i++)  {     for (j = 0; j < 6; j++)    {        arr[i * 6 + j] = bucket[i][j];    }  }}10.基數排序基本思想
  • 徹底搞懂穩定排序與不穩定排序
    排序算法如果是穩定的,那麼從一個鍵上排序,然後再從另一個鍵上排序,第一個鍵排序的結果可以為第二個鍵排序所用。基數排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,如果排序算法穩定,對基於比較的排序算法而言,元素交換的次數可能會少一些(個人感覺,沒有證實)。
  • JS家的排序算法 十大經典算法排序總結
    冒泡排序還有一種優化算法,就是立一個flag,當在一趟序列遍歷中元素沒有發生交換,則證明該序列已經有序。但這種改進對於提升性能來說並沒有什麼太大作用。。。什麼時候最快(Best Cases):當輸入的數據已經是正序時(都已經是正序了,我還要你冒泡排序有何用啊。。。。)
  • 排序算法——選擇排序(Selection Sort)
    選擇排序選擇排序是一種簡單直觀的排序算法,無論什麼數據進去都是 O(n²) 的時間複雜度。所以用到它的時候,數據規模越小越好。
  • 幾句話搞清八大排序算法,讓您在生活學習中不懼各種排序
    八大排序算法,分別是插入排序,冒泡排序,選擇排序,希爾排序,快速排序,堆排序,歸併排序,基數排序,搞了數年也沒有靜下心來,思考一下這些基本的算話,用到時,面試時,考試時,細細的看百度出的博客,即是耐下心看了一兩個,但是,還是一頭霧水!WHY?
  • 動畫詳解常用排序算法(1)
    剛學編程時大家都愛用冒泡排序,隨後接觸到選擇排序、插入排序等,歷史上還有曇花一現的希爾排序,公司面試時也經常會問到快速排序等等,小小的排序算法,融入了無數程序大牛的心血。如牛頓所言,正是站在巨人的肩膀上,我們才能望得更遠。本文我們就來一起梳理一下排序算法的前世今生。
  • 八大排序算法的 Python 實現
    [j] lists[j] = key j -= 1 return lists2、希爾排序希爾排序Shell Sort是插入排序的一種。 lists[i], lists[j] = lists[j], lists[i] return lists4、快速排序通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列