算法(二)初等排序前篇[插入和冒泡排序]

相關文章
算法(一)時間復雜度

前言

排序是算法的基礎,排序有很多種方法,有些方法實現起來很簡單,但是效率較差,我們可以將這些排序的方法稱之為初等排序。這篇文章我們就來學習初等排序中的插入排序和冒泡排序。

1.插入排序

插入排序比較容易想到,思路與打撲克時排列牌的順序是類似的。比如我們左手拿牌,然后用右手將牌從左到右,從小到大來排序,這就需要我們把需要進行排列的牌抽出來放到合適的位置,并且不斷的重復,直到牌的順序排好,這個過程就可以理解為插入排序。

圖解插入排序

插入排序過程中會將需要排序的數組,分為兩個部分:已排序部分和未排序部分,如下圖所示。


這里寫圖片描述

從圖中可以看出這個數組分為兩個部分,其中下標為0、1、2的元素為已排列部分,其余的則為未排列部分。

插入的排序規則:
將開頭元素視為以排序部分。接著執行如下的處理,直到沒有未排序部分。

  • 取出未排序部分的開頭元素賦值給臨時保存數據的變量v。
  • 在已排列的部分將所有比v大的元素向后移動一個位置。
  • 將取出的元素v插入空位。

按照這個規則,我們來舉一個簡單的例子。我們對數組 a={8,3,1,5,2,1} 進行從小到大排序,數組a如下圖所示。


這里寫圖片描述

我們對數組a進行排序,共需要5個步驟:
1.接著我們將a[0]=8視為已排序,我們從a[1]開始操作,將a[1]的值3取出,3要小于a[0]的值8,因此將a[0]的值8移動到a[1],再把3插入到a[0],如下圖所示。

這里寫圖片描述

2.a[2]的值1要比a[0]和a[1]的值要小,則將a[0]和a[1]順次向后移一個位置,然后將1插入a[0],如下圖所示。

這里寫圖片描述

3.將a[3]中的5拿出來,比它大的是a[2]的8,因此8向后移,將5插入a[3]。如下圖所示。


這里寫圖片描述

4.將a[4]中2拿出來,發現a[1]、a[2]、a[3]中的值都比2大,因此將它們依次向后移,將2插入到a[1]中,如下圖所示。


這里寫圖片描述

5.最后將a[5]中的1移到合適的位置,過程和上面一樣,最后的排序結果如下圖所示。


這里寫圖片描述

實現插入排序

接下來要實現插入排序,針對下圖來定義變量。

這里寫圖片描述

如上圖所示,i代表未排序部分的開頭元素,v是臨時保存a[i]值的變量, j代表已排序部分v要插入的位置。
根據定義的這三個變量,插入排序的實現思路就是:外層循環i從1開始自增,并在每次循環開始時將a[i]的值保存在v中;內層循環則是j從i-1開始向前自減,并將比v大的元素從a[j]移動到a[j+1],并將v插入到當前j+1的位置(內層循環后j會先自減1,因此插入的地方則是j+1的位置),當j等于-1或者a[j]小于等于v則內層循環結束。
接下來我們用代碼來實現插入排序,如下所示。


public class InsertSort {
    public static void main(String[] args) {
        int a[] = {8, 3, 1, 5, 2, 1};
        ArrayUtils.printArray(a);
        int b[] = insert(a);
        ArrayUtils.printArray(b);
    }

    public static int[] insert(int[] a) {
        int i, j, v;
        int n = a.length;
        for (i = 1; i < n; i++) {
            v = a[i];
            j = i - 1;
            while (j >= 0 && a[j] > v) {
                a[j + 1] = a[j];
                j--;
            }
            a[j + 1] = v;
        }
        return a;
    }
}


其中負責打印數組的ArrayUtils類如下所示。

public class ArrayUtils {
    public static void printArray(int[] array) {
        System.out.print("{");
        int len=array.length;
        for (int i = 0; i < len; i++) {
            System.out.print(array[i]);
            if (i < len - 1) {
                System.out.print(", ");
            }
        }
        System.out.println("}");
    }
}

輸出結果為:
{8, 3, 1, 5, 2, 1}
{1, 1, 2, 3, 5, 8}

插入排序的復雜度

根據算法(一)時間復雜度所講的,我們來算一下插入排序的時間復雜度。在最壞的情況下,每個i循環都需要執行i次移動,總共需要1+2+......+n-1=n2/2+n/2,根據此前講過的推導大O階的規則的我們得出插入排序的時間復雜度為O(n2)。

2.冒泡排序

冒泡排序應該是開發者最容易理解的排序算法,它的基本思想就是每次比較兩個相鄰的元素,如果它們的順序錯誤就把它們交換過來。需要進行排序的元素則向水中的氣泡一樣慢慢的移向水面。

圖解冒泡排序

與插入排序一樣,需要進行冒泡排序的數組也分為已排序部分和未排序部分。
冒泡排序的規則為:從數組末尾開始依次比較相鄰的兩個元素,如果大小關系相反則交換位置,直到數組中不再有順序相反的相鄰元素。

我們對數組 a={5,3,2,4,1} 進行從小到大排序,排序過程如下所示。
第一輪排序:

這里寫圖片描述

我們將數組末尾的a[4]的值和a[3]的值進行對比,發現a[4]的值比a[3]的值小,則將它們交換,再接著對剩下的相鄰的兩個元素進行對比和交換,最終得到的結果為a={1,5,3,2,4},已排序的部分的元素為1。

第二輪排序:

這里寫圖片描述

首先對比a[3]和a[4]的值,發現a[3]的值比a[4]的值小,則不需要進行排序。最終得到的結果為a={1,2,5,3,4},已排序部分的元素為1、2。

第三輪排序:


這里寫圖片描述

經過第三輪排序,已排序部分的元素為1、2、3。

第四輪排序:

這里寫圖片描述

經過四輪排序我們最終得到的結果為a={1,2,3,4,5}

實現冒泡排序

實現插入排序時,我們要先定義兩個變量,i為循環變量,表示未排序部分的開頭元素,從數組開頭向末尾移動。j也為循環變量,用于對未排序部分中相鄰元素兩兩比較,從數組的末尾n-1開始減小到 i 結束(i=1)。

這里寫圖片描述

代碼實現如下所示。

public class BubbleSort {
    public static void main(String[] args) {
        int a[] = {5, 3, 2, 4, 1};
        ArrayUtils.printArray(a);
        int b[] = bubble(a);
        ArrayUtils.printArray(b);
    }

    public static int[] bubble(int[] a) {
        int i, j, v;
        int n = a.length;
        for (i = 1; i <= n - 1; i++) {
            for (j = n - 1; j >= i ; j--) {
                if (a[j] < a[j - 1]) {
                    v = a[j];
                    a[j] = a[j - 1];
                    a[j - 1] = v;
                }
            }
        }
        return a;
    }
}

其中ArrayUtils的printArray方法此前講過,這里就不再給出,打印結果為:
{5, 3, 2, 4, 1}
{1, 2, 3, 4, 5}

冒泡排序的復雜度

最壞的情況下,冒泡排序對未排序部分的相鄰元素進行了(n-1)+(n-2)+(n-3)+……+1次比較,也就是n2/2+n/2次比較,根據推導大O階的規則我們得出冒泡排序的時間復雜度為O(n2)。

github源碼


歡迎關注我的微信公眾號,第一時間獲得博客更新提醒,以及更多成體系的Android相關技術干貨。
掃一掃下方二維碼即可關注:

enter image description here

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容

  • 數據結構與算法--排序之冒泡、選擇、插入、希爾 我們關注的主要對象是重新排列數組元素的算法,每個元素都有一個主鍵,...
    sunhaiyu閱讀 1,154評論 2 12
  • 概述 排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    蟻前閱讀 5,209評論 0 52
  • 概述:排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,739評論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個記錄插入到已排序好...
    依依玖玥閱讀 1,266評論 0 2
  • 一張老照片追溯著 遙遠的過去 春天里拿著鐮刀地里挖野菜 夏天里拿網河里去捕魚 秋天里背著花簍山上采鮮蘑菇 冬天里圍...
    夢雪他鄉閱讀 558評論 20 28