坐在馬桶上看算法:鄰居好說話,冒泡排序

2021-02-11 野狗


冒泡排序的基本思想是:每次比較兩個相鄰的元素,如果他們的順序錯誤就把他們交換過來。


簡化版的桶排序不僅僅有上一節所遺留的問題,更要命的是:它非常浪費空間!例如需要排序數的範圍是0~2100000000之間,那你則需要申請2100000001個變量,也就是說要寫成int a[2100000001]。因為我們需要用2100000001個「桶」來存儲0~2100000000之間每一個數出現的次數。即便只給你5個數進行排序(例如這5個數是1,1912345678,2100000000,18000000和912345678),你也仍然需要2100000001個「桶」,這真是太浪費了空間了!還有,如果現在需要排序的不再是整數而是一些小數,比如將5.56789,2.12,1.1,3.123,4.1234這五個數進行從小大排序又該怎麼辦呢?現在我們來學習另一種新的排序算法:冒泡排序。它可以很好的解決這兩個問題。

冒泡排序的基本思想是:每次比較兩個相鄰的元素,如果他們的順序錯誤就把他們交換過來。

例如我們需要將【12、35、99、18、76】這 5 個數進行從大到小進行排序。既然是從大到小排序也就是說越小的越靠後,你是不是覺得我在說廢話,但是這句話很關鍵 (∩_∩)。

首先比較第1位和第2位的大小,現在第1位是12,第2位是35。發現12比35要小,因為我們希望越小越靠後嘛,因此需要交換這兩個數的位置。交換之後這5個數的順序是35 12 99 18 76。

按照剛才的方法,繼續比較第2位和第3位的大小,第2位是12,第3位是99。12比99要小,因此需要交換這兩個數的位置。交換之後這5個數的順序是35 99 12 18 76。

根據剛才的規則,繼續比較第3位和第4位的大小,如果第3位比第4位小,則交換位置。交換之後這5個數的順序是35 99 18 12 76。

最後,比較第4位和第5位。4次比較之後5個數的順序是35 99 18 76 12。

經過4次比較後我們發現最小的一個數已經就位(已經在最後一位,請注意12這個數的移動過程),是不是很神奇。現在再來回憶一下剛才比較的過程。每次都是比較相鄰的兩個數,如果後面的數比前面的數大,則交換這兩個數的位置。一直比較下去直到最後兩個數比較完畢後,最小的數就在最後一個了。就如同是一個氣泡,一步一步往後「翻滾」,直到最後一位。所以這個排序的方法有一個很好聽的名字「冒泡排序」。


說道這裡其實我們的排序只將5個數中最小的一個歸位了。每將一個數歸位我們將其稱為「一趟」。下面我們將繼續重複剛才的過程,將剩下的4個數一一歸位。

好現在開始「第二趟」,目標是將第2小的數歸位。首先還是先比較第1位和第2位,如果第1位比第2位小,則交換位置。交換之後這5個數的順序是99 35 18 76 12。接下來你應該都會了,依次比較第2位和第3位,第3位和第4位。注意此時已經不需要再比較第4位和第5位。因為在第一趟結束後已經可以確定第5位上放的是最小的了。第二趟結束之後這5個數的順序是99 35 76 18 12。

第三趟」也是一樣的。第三趟之後這5個數的順序是99 76 35 18 12。

現在到了最後一趟「第四趟」。有的同學又要問了,這不是已經排好了嗎?還要繼續?當然,這裡純屬巧合,你可以用別的數試一試可能就不是了。你能找出這樣的數據樣例來嗎?請試一試。

「冒泡排序」原理是:每一趟只能確定將一個數歸位。即第一趟只能確定將末位上的數(既第5位)歸位,第二趟只能將倒數第2位上的數(既第4位)歸位,第三趟只能將倒數第3位上的數(既第3位)歸位,而現在前面還有兩個位置上的數沒有歸位,因此我們仍然需要進行「第四趟」。

「第四趟」只需要比較第1位和第2位的大小。因為後面三個位置上的數歸位了,現在第1位是99,第2位是76,無需交換。這5個數的順序不變仍然是99 76 35 18 12。到此排序完美結束了,5個數已經有4個數歸位,那最後一個數也只能放在第1位了。

最後我們總結一下:如果有n個數進行排序,只需將n-1個數歸位,也就是說要進行n-1趟操作。而「每一趟」都需要從第1位開始進行相鄰兩個數的比較,將較小的一個數放在後面,比較完畢後向後挪一位繼續比較下面兩個相鄰數的大小,重複此步驟,直到最後一個尚未歸位的數,已經歸位的數則無需再進行比較(已經歸位的數你還比較個啥,浪費表情)。

這個算法是不是很強悍。記得我每次拍集體照的時候就總是被別人換來換去的,當時特別煩。不知道發明此算法的人當時的靈感是否來源於此。羅裡吧嗦地說了這麼多,下面是代碼。建議先自己嘗試去實現一下看看,再來看我是如何實現的。

#include <stdio.h>

int main()

{

  int a[100],i,j,t,n;

    scanf("%d",&n);  //輸入一個數n,表示接下來有n個數

    for(i=1;i<=n;i++)  //循環讀入n個數到數組a中

        scanf("%d",&a[i]);

    //冒泡排序的核心部分

    for(i=1;i<=n-1;i++) //n個數排序,只用進行n-1趟

    {

        for(j=1;j<=n-i;j++) //從第1位開始比較直到最後一個尚未歸位的數,想一想為什麼到n-i就可以了。

        {

            if(a[j]<a[j+1]) //比較大小並交換

            {  t=a[j]; a[j]=a[j+1]; a[j+1]=t;  }

        }

    }

    for(i=1;i<=n;i++)  //輸出結果

        printf("%d ",a[i]);

    getchar();getchar();

    return 0;

}

可以輸入以下數據進行驗證

1081005022156110009990

運行結果是

01681522501009991000

將上面代碼稍加修改,就可以解決第1節遺留的問題,如下。

#include <stdio.h>

struct student

{

    char name[21];

    char score;

};//這裡創建了一個結構體用來存儲姓名和分數

int main()

{

    struct student a[100],t;

    int i,j,n;

    scanf("%d",&n); //輸入一個數n

    for(i=1;i<=n;i++) //循環讀入n個人名和分數

scanf("%s %d",a[i].name,&a[i].score);

    //按分數從高到低進行排序

    for(i=1;i<=n-1;i++)

    {

        for(j=1;j<=n-i;j++)

        {

            if(a[j].score<a[j+1].score)//對分數進行比較

            {  t=a[j]; a[j]=a[j+1]; a[j+1]=t;  }

        }

    }

    for(i=1;i<=n;i++)//輸出人名

        printf("%s\n",a[i].name);

    getchar();getchar();

    return 0;

}

可以輸入以下數據進行驗證

5

huhu 5

haha 3

xixi 5

hengheng 2

gaoshou 8

運行結果是

gaoshou

huhu

xixi

haha

hengheng

冒泡排序的核心部分是雙重嵌套循環。不難看出冒泡排序的時間複雜度是O(N2)。這是一個非常高的時間複雜度。冒泡排序早在1956年就有人開始研究,之後有很多人都嘗試過對冒泡排序進行改進,但結果卻令人失望。如Knuth(Donald E. Knuth中文名為高德納,1974年圖靈獎獲得者)所說:「冒泡排序除了它迷人的名字和導致了某些有趣的理論問題這一事實之外,似乎沒有什麼值得推薦的。」你可能要問:那還有沒有更好的排序算法呢?請期待下周更新——快速排序。

作者:啊哈雷

原文:http://ahalei.blog.51cto.com/4767671/1364401


這裡,了解野狗!

相關焦點

  • Java實現冒泡排序算法
    #理由一:面試的時候,千萬不要被數據結構與算法拖了後腿#理由二: 你真的願意做一輩子CRUD Boy嗎#理由三: 不想寫出開源框架,中間件的工程師,不是好廚子1.2.如何系統化學習數據結構與算法?我想好了,還是需要學習數據結構與算法。但是我有兩個困惑:1.如何著手學習呢?2.有哪些內容要學習呢?
  • 冒泡排序算法的來龍去脈
    956年就有人開始研究冒泡排序,之後有很多人嘗試對其進行改進,但是結果令人失望。1974年圖靈獎獲得者Donald E. Knuth說:「冒泡排序除了它迷人的名字和導致了某些有趣的理論問題這一事實之外,似乎沒有什麼值得推薦的。」2 算法描述其基本思想是每次比較兩個相鄰的元素,如果它們順序錯誤就把它們交換過來。
  • 排序算法總結(1):冒泡排序
    冒泡排序是一種交換排序。什麼是交換排序呢?交換排序:兩兩比較待排序的關鍵字,並交換不滿足次序要求的那對數,直到整個表都滿足次序要求為止。算法思想它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。
  • 重溫7種排序算法 第一篇,交換排序算法:冒泡排序、快速排序
    排序算法可分為以下幾類:    交換排序算法:冒泡排序、快速排序;    選擇排序算法:簡單選擇排序、堆排序;    插入排序算法:直接插入排序、希爾排序;    歸併排序算法。    主要做了以上7種排序算法的筆記,字數可能較多,所以分為幾篇。
  • Python中的冒泡排序算法,冒泡排序的優缺點,中級python技術點
    Python中的冒泡排序算法冒泡排序是最直接的排序算法之一。它的名字來自於算法的工作方式:每經過一個新遍歷,列表中最大的元素就會向正確的位置「冒泡」。冒泡排序包括對列表進行多次遍歷、逐個比較元素以及交換順序混亂的相鄰項。
  • 排序算法之冒泡排序及其優化
    冒泡排序思想比較相鄰兩個元素,如果前面的元素比後面的元素大,則交換位置。最後一個元素必定會是最大值。排除掉最後一位元素,繼續循環,直至沒有元素需要比較可以看出,冒牌排序其實和選擇排序時很像的,只不過選擇排序是比較數據,先記錄下最小/大值的下標,等一趟循環結束的時候再交換位置;而冒泡排序在比較數據的同時也做了交換。性能時間複雜度與選擇排序一樣,時間複雜度為O(n^2)。
  • JS家的排序算法 十大經典算法排序總結
    ,但在Web的江湖,JavaScript可謂風頭無兩,坐上了頭把交椅。然而,在傳統的計算機算法和數據結構領域,大多數專業教材和書籍的默認語言都是Java或者C/C+ +。這給最近想惡補算法和數據結構知識的我造成了一定困擾,因為我想尋找一本以JavaScript為默認語言的算法書籍。
  • 看動畫學算法之:排序-冒泡排序
    簡介排序可能是所有的算法中最最基礎和最最常用的了。排序是一個非常經典的問題,它以一定的順序對一個數組(或一個列表)中的項進行重新排序。排序算法有很多種,每個都有其自身的優點和局限性。今天我們來學習最最簡單的冒泡排序算法。冒泡排序的原理冒泡排序的原理很簡單,我們想像一下一個一個的氣泡上浮的過程。
  • 輕鬆搞定Java冒泡排序算法以及算法優化
    作為Java程式設計師,簡單的算法,必須要掌握的。尤其初級開發人員在面試過程或者筆試都會有相應算法題,今天我們講解冒泡排序算法是如何實現的以及優化方法。何為冒泡排序冒泡排序的基本思路:通過對待排序系列從前向後,依次比較相鄰元素的值,若發現逆序就交換,意思就是使較大的元素從前向後移,好比水低下的氣泡一樣逐漸向上冒泡,一個道理的。冒泡排序優缺點優點:比較簡單、空間複雜度較低、是穩定的一種排序。
  • JavaScript算法之冒泡排序
    冒泡排序是討論最多的算法之一,它比較容易理解,但是效率較低。如果數組是已排序的,冒泡排序只需要遍歷一次數組,不過最壞的情況下運行時間為 O(n2),非常低效。儘管如此,理解這個算法依然很重要,需要明白它為什麼效率低下。本文將介紹實現冒泡排序的兩個思路。
  • Java中常見的排序算法有哪些?---冒泡排序
    排序相關的的基本概念排序: 將一組雜亂無章的數據按一定的規律順次排列起來。數據表( data list): 它是待排序數據對象的有限集合。排序碼(key):通常數據對象有多個屬性域,即多個數據成員組成,其中有一個屬性域可用來區分對象,作為排序依據。該域即為排序碼。
  • 圖文詳解冒泡排序
    當這樣的一趟操作完成時,序列中最大的未排序元素就被放置到了所有未排序的元素中最後的位置上,它就像水中的石塊一樣沉到了水底。而其它較小的元素則被移動到了序列的前面,就像水中的氣泡冒到了水面一樣。這就是為什麼該算法被叫做冒泡排序的原因。
  • 單集合排序:冒泡排序法
    在日常開發中經常會遇到一類問題,就是對一個集合的數據進行排序掌握一些排序算法,對於日常開發是非常有幫助今天介紹一下冒泡排序法01算法邏輯>02時間複雜度由上圖邏輯可以得出,冒泡排序的循環次數為由循環次數可以得出,冒泡排序的時間複雜度為03空間複雜度由上圖邏輯可以得出
  • 使用PHP完成冒泡排序算法
    原理本文使用的排序數組數據如下:$arr1 = array(18,22,12, 15,23,9);遍歷一個數組,在此過程中,將相鄰的兩個單元的值進行比較(倆倆相比,左邊比右邊大就對換位置):下方圖中所示為上面所列舉的算法過程:規律總結1.要進行從頭到尾兩兩比較並進行交換位置的趟數為$n-1趟,$n是總個數(數組長度)2.每次都對相鄰的兩個數據進行大小比較,如果需要,就交換他們的位置!
  • 冒泡排序算法由一個什麼循環控制? - php中文網
    本篇文章主要給大家介紹冒泡排序由一個什麼循環控制的,那麼冒泡排序算法可以由雙層for循環實現,也可以由單個for循環實現。下面我們就結合具體的代碼示例,給大家介紹冒泡排序的實現方法!一、什麼叫冒泡排序法?
  • Scratch3.0編程小課堂33(算法題:冒泡排序)
    生成隨機數列排序完成題目:系統隨機生成5個1到100的數,程序使用冒泡排序法對它們進行從小到大的排序;角色:小精靈;知識點:冒泡排序,列表(鍊表),變量,循環,多重選擇;知識普及:冒泡排序(Bubble Sort)這個算法的名字由來是因為越小的元素會經由交換慢慢「浮」到數列的頂端,就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣,故名「冒泡排序」。
  • 經典排序算法一 冒泡排序(JAVA實現)
    冒泡排序原理:相鄰的兩個元素進行比較,將值大的元素移動到右端。冒泡排序實現思路:遍歷要排序的元素,依次比較相鄰的兩個元素,值大的移動到右端,則第二次就可以忽略第一次遍歷放在最右端的元素,依次類推直到遍歷到n-1次只剩下2個元素進行比較,冒泡排序結束。
  • Java、Python冒泡排序法
    冒泡排序算法思想:讓數組中的兩個相鄰數字進行比較,數組中較大的值向下沉,值小的上浮,就類似於水中的氣泡,較大的下沉,較小的上升,慢慢冒出來。簡單的說就是數值大的會慢慢往前排,數據值小的會慢慢向後排,最終實現由小到達排列,最小的排在最前,最大的排到最後。
  • 圖解C語言冒泡排序算法,含代碼分析
    冒泡排序算法的原理
  • 面試官問我插入排序和冒泡排序哪個更牛逼?
    還有一些其他經典的排序,小鹿整理的共有十種是面試常問到的,冒泡排序、插入排序、希爾排序、選擇排序、歸併排序、快速排序、堆排序、桶排序、計數排序、基數排序。雖然我們基本知道了這些排序算法,但是在實際項目開發以及面試中往往出乎我們所料。在面試中,經常會被問到各種排序之間的比較;在實際項目中,往往排序的數據不是我們所練習的整數。