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

相關(guān)文章
算法(一)時(shí)間復(fù)雜度

前言

排序是算法的基礎(chǔ)摇邦,排序有很多種方法此改,有些方法實(shí)現(xiàn)起來(lái)很簡(jiǎn)單趾撵,但是效率較差,我們可以將這些排序的方法稱之為初等排序共啃。這篇文章我們就來(lái)學(xué)習(xí)初等排序中的插入排序和冒泡排序占调。

1.插入排序

插入排序比較容易想到,思路與打撲克時(shí)排列牌的順序是類(lèi)似的移剪。比如我們左手拿牌究珊,然后用右手將牌從左到右,從小到大來(lái)排序纵苛,這就需要我們把需要進(jìn)行排列的牌抽出來(lái)放到合適的位置剿涮,并且不斷的重復(fù),直到牌的順序排好赶站,這個(gè)過(guò)程就可以理解為插入排序幔虏。

圖解插入排序

插入排序過(guò)程中會(huì)將需要排序的數(shù)組,分為兩個(gè)部分:已排序部分和未排序部分贝椿,如下圖所示想括。


這里寫(xiě)圖片描述

從圖中可以看出這個(gè)數(shù)組分為兩個(gè)部分,其中下標(biāo)為0烙博、1瑟蜈、2的元素為已排列部分烟逊,其余的則為未排列部分。

插入的排序規(guī)則:
將開(kāi)頭元素視為以排序部分铺根。接著執(zhí)行如下的處理宪躯,直到?jīng)]有未排序部分。

  • 取出未排序部分的開(kāi)頭元素賦值給臨時(shí)保存數(shù)據(jù)的變量v位迂。
  • 在已排列的部分將所有比v大的元素向后移動(dòng)一個(gè)位置访雪。
  • 將取出的元素v插入空位。

按照這個(gè)規(guī)則掂林,我們來(lái)舉一個(gè)簡(jiǎn)單的例子臣缀。我們對(duì)數(shù)組 a={8,3,1,5,2,1} 進(jìn)行從小到大排序,數(shù)組a如下圖所示泻帮。


這里寫(xiě)圖片描述

我們對(duì)數(shù)組a進(jìn)行排序精置,共需要5個(gè)步驟:
1.接著我們將a[0]=8視為已排序,我們從a[1]開(kāi)始操作锣杂,將a[1]的值3取出脂倦,3要小于a[0]的值8,因此將a[0]的值8移動(dòng)到a[1]元莫,再把3插入到a[0]赖阻,如下圖所示。

這里寫(xiě)圖片描述

2.a[2]的值1要比a[0]和a[1]的值要小踱蠢,則將a[0]和a[1]順次向后移一個(gè)位置政供,然后將1插入a[0],如下圖所示朽基。

這里寫(xiě)圖片描述

3.將a[3]中的5拿出來(lái),比它大的是a[2]的8离陶,因此8向后移稼虎,將5插入a[3]。如下圖所示招刨。


這里寫(xiě)圖片描述

4.將a[4]中2拿出來(lái)霎俩,發(fā)現(xiàn)a[1]、a[2]沉眶、a[3]中的值都比2大打却,因此將它們依次向后移,將2插入到a[1]中谎倔,如下圖所示柳击。


這里寫(xiě)圖片描述

5.最后將a[5]中的1移到合適的位置,過(guò)程和上面一樣片习,最后的排序結(jié)果如下圖所示捌肴。


這里寫(xiě)圖片描述

實(shí)現(xiàn)插入排序

接下來(lái)要實(shí)現(xiàn)插入排序蹬叭,針對(duì)下圖來(lái)定義變量。

這里寫(xiě)圖片描述

如上圖所示状知,i代表未排序部分的開(kāi)頭元素秽五,v是臨時(shí)保存a[i]值的變量, j代表已排序部分v要插入的位置饥悴。
根據(jù)定義的這三個(gè)變量坦喘,插入排序的實(shí)現(xiàn)思路就是:外層循環(huán)i從1開(kāi)始自增,并在每次循環(huán)開(kāi)始時(shí)將a[i]的值保存在v中西设;內(nèi)層循環(huán)則是j從i-1開(kāi)始向前自減瓣铣,并將比v大的元素從a[j]移動(dòng)到a[j+1],并將v插入到當(dāng)前j+1的位置(內(nèi)層循環(huán)后j會(huì)先自減1济榨,因此插入的地方則是j+1的位置)坯沪,當(dāng)j等于-1或者a[j]小于等于v則內(nèi)層循環(huán)結(jié)束。
接下來(lái)我們用代碼來(lái)實(shí)現(xiàn)插入排序擒滑,如下所示腐晾。


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;
    }
}


其中負(fù)責(zé)打印數(shù)組的ArrayUtils類(lèi)如下所示。

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("}");
    }
}

輸出結(jié)果為:
{8, 3, 1, 5, 2, 1}
{1, 1, 2, 3, 5, 8}

插入排序的復(fù)雜度

根據(jù)算法(一)時(shí)間復(fù)雜度所講的丐一,我們來(lái)算一下插入排序的時(shí)間復(fù)雜度藻糖。在最壞的情況下,每個(gè)i循環(huán)都需要執(zhí)行i次移動(dòng)库车,總共需要1+2+......+n-1=n2/2+n/2巨柒,根據(jù)此前講過(guò)的推導(dǎo)大O階的規(guī)則的我們得出插入排序的時(shí)間復(fù)雜度為O(n2)。

2.冒泡排序

冒泡排序應(yīng)該是開(kāi)發(fā)者最容易理解的排序算法柠衍,它的基本思想就是每次比較兩個(gè)相鄰的元素洋满,如果它們的順序錯(cuò)誤就把它們交換過(guò)來(lái)。需要進(jìn)行排序的元素則向水中的氣泡一樣慢慢的移向水面珍坊。

圖解冒泡排序

與插入排序一樣牺勾,需要進(jìn)行冒泡排序的數(shù)組也分為已排序部分和未排序部分。
冒泡排序的規(guī)則為:從數(shù)組末尾開(kāi)始依次比較相鄰的兩個(gè)元素阵漏,如果大小關(guān)系相反則交換位置驻民,直到數(shù)組中不再有順序相反的相鄰元素。

我們對(duì)數(shù)組 a={5,3,2,4,1} 進(jìn)行從小到大排序履怯,排序過(guò)程如下所示回还。
第一輪排序:

這里寫(xiě)圖片描述

我們將數(shù)組末尾的a[4]的值和a[3]的值進(jìn)行對(duì)比,發(fā)現(xiàn)a[4]的值比a[3]的值小叹洲,則將它們交換柠硕,再接著對(duì)剩下的相鄰的兩個(gè)元素進(jìn)行對(duì)比和交換,最終得到的結(jié)果為a={1,5,3,2,4}运提,已排序的部分的元素為1仅叫。

第二輪排序:

這里寫(xiě)圖片描述

首先對(duì)比a[3]和a[4]的值帜篇,發(fā)現(xiàn)a[3]的值比a[4]的值小,則不需要進(jìn)行排序诫咱。最終得到的結(jié)果為a={1,2,5,3,4}笙隙,已排序部分的元素為1、2坎缭。

第三輪排序:


這里寫(xiě)圖片描述

經(jīng)過(guò)第三輪排序竟痰,已排序部分的元素為1、2掏呼、3坏快。

第四輪排序:

這里寫(xiě)圖片描述

經(jīng)過(guò)四輪排序我們最終得到的結(jié)果為a={1,2,3,4,5}

實(shí)現(xiàn)冒泡排序

實(shí)現(xiàn)插入排序時(shí),我們要先定義兩個(gè)變量憎夷,i為循環(huán)變量莽鸿,表示未排序部分的開(kāi)頭元素,從數(shù)組開(kāi)頭向末尾移動(dòng)拾给。j也為循環(huán)變量祥得,用于對(duì)未排序部分中相鄰元素兩兩比較,從數(shù)組的末尾n-1開(kāi)始減小到 i 結(jié)束(i=1)蒋得。

這里寫(xiě)圖片描述

代碼實(shí)現(xiàn)如下所示级及。

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方法此前講過(guò),這里就不再給出额衙,打印結(jié)果為:
{5, 3, 2, 4, 1}
{1, 2, 3, 4, 5}

冒泡排序的復(fù)雜度

最壞的情況下饮焦,冒泡排序?qū)ξ磁判虿糠值南噜徳剡M(jìn)行了(n-1)+(n-2)+(n-3)+……+1次比較,也就是n2/2+n/2次比較窍侧,根據(jù)推導(dǎo)大O階的規(guī)則我們得出冒泡排序的時(shí)間復(fù)雜度為O(n2)县踢。

github源碼


歡迎關(guān)注我的微信公眾號(hào),第一時(shí)間獲得博客更新提醒伟件,以及更多成體系的Android相關(guān)技術(shù)干貨殿雪。
掃一掃下方二維碼即可關(guān)注:

enter image description here

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锋爪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌爸业,老刑警劉巖其骄,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扯旷,居然都是意外死亡拯爽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)钧忽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)毯炮,“玉大人逼肯,你說(shuō)我怎么就攤上這事√壹澹” “怎么了篮幢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)为迈。 經(jīng)常有香客問(wèn)我三椿,道長(zhǎng),這世上最難降的妖魔是什么葫辐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任搜锰,我火速辦了婚禮,結(jié)果婚禮上耿战,老公的妹妹穿的比我還像新娘蛋叼。我一直安慰自己,他們只是感情好剂陡,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布狈涮。 她就那樣靜靜地躺著,像睡著了一般鹏倘。 火紅的嫁衣襯著肌膚如雪薯嗤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天纤泵,我揣著相機(jī)與錄音骆姐,去河邊找鬼。 笑死捏题,一個(gè)胖子當(dāng)著我的面吹牛玻褪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播公荧,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼带射,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了循狰?” 一聲冷哼從身側(cè)響起窟社,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绪钥,沒(méi)想到半個(gè)月后灿里,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡程腹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年匣吊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡色鸳,死狀恐怖社痛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情命雀,我是刑警寧澤蒜哀,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站咏雌,受9級(jí)特大地震影響凡怎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赊抖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一统倒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氛雪,春花似錦房匆、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至弦追,卻和暖如春岳链,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劲件。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工掸哑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人零远。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓苗分,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親牵辣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子摔癣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 數(shù)據(jù)結(jié)構(gòu)與算法--排序之冒泡、選擇膳帕、插入、希爾 我們關(guān)注的主要對(duì)象是重新排列數(shù)組元素的算法,每個(gè)元素都有一個(gè)主鍵危彩,...
    sunhaiyu閱讀 1,145評(píng)論 2 12
  • 概述 排序有內(nèi)部排序和外部排序攒磨,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大汤徽,一次不能容納全部...
    蟻前閱讀 5,188評(píng)論 0 52
  • 概述:排序有內(nèi)部排序和外部排序娩缰,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大谒府,一次不能容納全部...
    每天刷兩次牙閱讀 3,733評(píng)論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,260評(píng)論 0 2
  • 一張老照片追溯著 遙遠(yuǎn)的過(guò)去 春天里拿著鐮刀地里挖野菜 夏天里拿網(wǎng)河里去捕魚(yú) 秋天里背著花簍山上采鮮蘑菇 冬天里圍...
    夢(mèng)雪他鄉(xiāng)閱讀 555評(píng)論 20 28