算法(4)-常見的排序算法

前言

說到算法饮睬,就不得不說一下排序了沈跨,相信很多人的算法是從排序開始的,哪怕是算法導(dǎo)論這本書煤杀,也是從排序開始講的算法眷蜈,所以在說完了之前的各種算法是思想之后,是時候真刀真槍的干活了沈自。這一篇就說說算法中經(jīng)常遇到的各種排序算法(代碼使用kotlin實現(xiàn))

  1. 冒泡排序
  2. 選擇排序
  3. 插入排序
  4. 希爾排序
  5. 快速排序
  6. 歸并排序

冒泡排序和選擇排序

為什么把這兩個放一起說呢,說到排序算法辜妓,冒泡排序和選擇排序可謂是基礎(chǔ)中的基礎(chǔ)了枯途,拿這兩個熱身是再好不過了

冒泡排序

定義

冒泡排序(Bubble Sort)忌怎,是一種計算機科學(xué)領(lǐng)域的較簡單的排序算法。
它重復(fù)地走訪過要排序的元素列酪夷,依次比較兩個相鄰的元素榴啸,如果他們的順序(如從大到小、首字母從A到Z)錯誤就把他們交換過來晚岭。走訪元素的工作是重復(fù)地進(jìn)行直到?jīng)]有相鄰元素需要交換鸥印,也就是說該元素已經(jīng)排序完成。
這個算法的名字由來是因為越大的元素會經(jīng)由交換慢慢“浮”到數(shù)列的頂端(升序或降序排列)坦报,就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣库说,故名“冒泡排序”

具體實現(xiàn)

fun bubbleSort(arr: IntArray?) {
    if (arr == null || arr.size == 0)
        return
    for (i in 0 until arr.size - 1) {
        for (j in arr.size - 1 downTo i + 1) {
            if (arr[j] < arr[j - 1]) {
                swap(arr, j - 1, j)
            }
        }
    }
}

選擇排序

定義

選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工作原理是每一次從待排序的數(shù)據(jù)元素中選出最衅瘛(或最大)的一個元素潜的,存放在序列的起始位置,然后字管,再從剩余未排序元素中繼續(xù)尋找最袉病(大)元素,然后放到已排序序列的末尾嘲叔。以此類推亡呵,直到全部待排序的數(shù)據(jù)元素排完。 選擇排序是不穩(wěn)定的排序方法

具體實現(xiàn)

fun selectSort(arr: IntArray?) {
    if (arr == null || arr.size == 0)
        return
    var minIndex = 0
    for (i in 0 until arr.size - 1) { //只需要比較n-1次
        minIndex = i
        for (j in i + 1 until arr.size) { //從i+1開始比較硫戈,因為minIndex默認(rèn)為i了锰什,i就沒必要比了。
            if (arr[j] < arr[minIndex]) {
                minIndex = j
            }
        }

        if (minIndex != i) { //如果minIndex不為i掏愁,說明找到了更小的值歇由,交換之。
            swap(arr, i, minIndex)
        }
    }

}

冒泡排序和選擇排序最標(biāo)志性的特征就是雙重for循環(huán)了果港,這也說明了沦泌,效率低的時候簡直不忍直視,這里就不多說了

插入排序和希爾排序

說完了冒泡排序和選擇排序辛掠,就接下來說說這兩貨了谢谦,插入排序和希爾排序,這兩貨的思想相差不大萝衩,甚至可以用一篇代碼實現(xiàn)回挽,自然就放一起了

插入排序

定義

插入排序(英語:Insertion Sort)是一種簡單直觀的排序算法。它的工作原理是通過構(gòu)建有序序列猩谊,對于未排序數(shù)據(jù)千劈,在已排序序列中從后向前掃描,找到相應(yīng)位置并插入牌捷。其實我們玩撲克牌時的排序墙牌,用的就是插入排序

具體實現(xiàn)

fun insertSort(arr: IntArray?) {
    if (arr == null || arr.size == 0)
        return
    for (i in 1 until arr.size) {

        var j = i
        val target = arr[i]

        //后移
        while (j >= 1 && target < arr[j - 1]) {
            arr[j] = arr[j - 1]
            j--
        }

        //插入
        arr[j] = target
    }

}

希爾排序

定義

希爾排序涡驮,也稱遞減增量排序算法,是插入排序的一種更高效的改進(jìn)版本喜滨。希爾排序是非穩(wěn)定排序算法


希爾排序是基于插入排序的以下兩點性質(zhì)而提出改進(jìn)方法的:
插入排序在對幾乎已經(jīng)排好序的數(shù)據(jù)操作時捉捅,效率高,即可以達(dá)到線性排序的效率
但插入排序一般來說是低效的虽风,因為插入排序每次只能將數(shù)據(jù)移動一位

具體實現(xiàn)

fun shellSort(arr: IntArray) {
    if (arr == null || arr.size == 0)
        return
    var step = arr.size / 2
    while (step > 0) {
        for (i in step until arr.size) {
            var j = i
            var target = arr[i]

            while (j >= step && target < arr[j - step]) {  //從后向前棒口,找到比其小的數(shù)的位置
                arr[j] = arr[j - step]  //向后挪動
                j -= step
            }

            if (j != i)    //存在比其小的數(shù)
                arr[j] = target
        }
        step /= 2
    }
}

仔細(xì)看插入排序和希爾排序的代碼,是不是發(fā)現(xiàn)兩者很相似辜膝,如果將希爾排序中的step設(shè)置為1无牵,那么它就是插入排序了,所以我說内舟,這兩者甚至可以用一篇代碼實現(xiàn)

快速排序和歸并排序

接下來再說說快速排序和歸并排序合敦,之前在分治法的文中提到了這兩種排序算法,它們都是分治法思想的算法验游,所以這里也是放一起說明

快速排序

定義

通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨立的兩部分充岛,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序耕蝉,整個排序過程可以遞歸進(jìn)行崔梗,以此達(dá)到整個數(shù)據(jù)變成有序序列

具體實現(xiàn)

例如如圖:


  1. 首先設(shè)置兩個變量分別從頭和尾進(jìn)行索引
  2. 將第一個元素3存儲起來temp
  3. 從尾向前索引,找到第一個比3小的元素垒在,放入3的位置蒜魄,尾部索引減1,然后再從頭向尾索引场躯,找到第一個比3大的元素9谈为,放入0的位置,頭部索引加1
  4. 重復(fù)2踢关,3兩步伞鲫,知道兩個索引變量在某次減1或者加1的時候相等時為一次快速排序,然后以這個相等的變量為分割签舞,分別將它左邊和右邊的數(shù)組再次進(jìn)行同樣的快速排序操作秕脓,直到排序結(jié)束
  5. 例如這個數(shù)組,第二次從尾部索引找比3小的元素2儒搭,放入9的位置吠架,然后從頭部索引找比3大的元素,當(dāng)頭部索引和尾部索引都指向2時搂鲫,雖然此時頭部索引還沒有找到比3大的元素傍药,但是已經(jīng)完成一次快速排序了,所以講3放入此時索引指向的位置,這樣一次快速排序就結(jié)束了怔檩,然后不斷是循環(huán)即可
//快速排序    左閉右開
fun quickSort(arr: IntArray, left: Int, right: Int) {
    if (left >= right)
        return
    val pivotPos = partition(arr, left, right)
    quickSort(arr, left, pivotPos - 1)
    quickSort(arr, pivotPos + 1, right)
}
//一個循環(huán)
fun partition(arr: IntArray, left: Int, right: Int): Int {
    var left = left
    var right = right
    val pivotKey = arr[left]

    while (left < right) {
        while (left < right && arr[right] >= pivotKey)
            right--
        arr[left] = arr[right] //把小的移動到左邊
        while (left < right && arr[left] <= pivotKey)
            left++
        arr[right] = arr[left] //把大的移動到右邊
    }
    arr[left] = pivotKey //最后把pivot賦值到中間
    return left
}

歸并排序

定義

歸并排序是一個典型分治法思想的排序褪秀,它的思想是蓄诽,如果兩個序列是有序的薛训,那么將它們合成,依然可以得到一個有序序列仑氛,而對于一個無需的序列乙埃,將它拆分為足夠小的序列然后進(jìn)行排序,最后將這些有序序列合并锯岖,那么就可以得到一個有序的序列

具體實現(xiàn)

//歸并排序 
fun mergeSort(array: IntArray, left: Int, right: Int) {
    if (left == right) {
        return
    } else {
        val mid = (left + right) / 2
        mergeSort(array, left, mid)//左邊
        mergeSort(array, mid + 1, right)//右邊
        merge(array, left, mid + 1, right)//合并
    }
}

//合并
fun merge(array: IntArray, left: Int, mid: Int, right: Int) {
    val leftSize = mid - left
    val rightSize = right - mid + 1
    //生成數(shù)組
    val leftArray = IntArray(leftSize)
    val rightArray = IntArray(rightSize)
    //填充左邊的數(shù)組
    for (i in left until mid) {
        leftArray[i - left] = array[i]
    }
    //填充右邊的數(shù)組
    for (i in mid..right) {
        rightArray[i - mid] = array[i]
    }

    //合并數(shù)組
    var i = 0
    var j = 0
    var k = left
    while (i < leftSize && j < rightSize) {
        if (leftArray[i] < rightArray[j]) {
            array[k] = leftArray[i]
            k++
            i++
        } else {
            array[k] = rightArray[j]
            k++
            j++
        }
    }
    while (i < leftSize) {//左邊剩余數(shù)據(jù)
        array[k] = leftArray[i]
        k++
        i++
    }
    while (j < rightSize) {//右邊剩余數(shù)據(jù)
        array[k] = rightArray[j]
        k++
        j++
    }

}

當(dāng)然介袜,還有很多各式各樣的排序算法,這里就不一樣列舉了出吹,大家有興趣可以自行探索

參考資料:
https://www.cnblogs.com/onepixel/articles/7674659.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遇伞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捶牢,更是在濱河造成了極大的恐慌鸠珠,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秋麸,死亡現(xiàn)場離奇詭異渐排,居然都是意外死亡,警方通過查閱死者的電腦和手機灸蟆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門驯耻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炒考,你說我怎么就攤上這事可缚。” “怎么了斋枢?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵帘靡,是天一觀的道長。 經(jīng)常有香客問我杏慰,道長测柠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任缘滥,我火速辦了婚禮轰胁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朝扼。我一直安慰自己赃阀,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著榛斯,像睡著了一般观游。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驮俗,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天懂缕,我揣著相機與錄音,去河邊找鬼王凑。 笑死搪柑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的索烹。 我是一名探鬼主播工碾,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼百姓!你這毒婦竟也來了渊额?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤垒拢,失蹤者是張志新(化名)和其女友劉穎旬迹,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體子库,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡舱权,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仑嗅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宴倍。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖仓技,靈堂內(nèi)的尸體忽然破棺而出鸵贬,到底是詐尸還是另有隱情,我是刑警寧澤脖捻,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布阔逼,位于F島的核電站,受9級特大地震影響地沮,放射性物質(zhì)發(fā)生泄漏嗜浮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一摩疑、第九天 我趴在偏房一處隱蔽的房頂上張望危融。 院中可真熱鬧,春花似錦雷袋、人聲如沸吉殃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛋勺。三九已至瓦灶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抱完,已是汗流浹背贼陶。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乾蛤,地道東北人每界。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像家卖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子庙楚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

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

  • 總結(jié)一下常見的排序算法上荡。 排序分內(nèi)排序和外排序。內(nèi)排序:指在排序期間數(shù)據(jù)對象全部存放在內(nèi)存的排序馒闷。外排序:指在排序...
    jiangliang閱讀 1,354評論 0 1
  • 排序的基本概念 在計算機程序開發(fā)過程中酪捡,經(jīng)常需要一組數(shù)據(jù)元素(或記錄)按某個關(guān)鍵字進(jìn)行排序,排序完成的序列可用于快...
    Jack921閱讀 1,438評論 1 4
  • 概述 排序有內(nèi)部排序和外部排序纳账,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序逛薇,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,191評論 0 52
  • 關(guān)于睡眠的報道,我已經(jīng)在一些日報的公眾號上看過卧秘,但是我依然覺得我的睡眠質(zhì)量不怎么好呢袱,晚上要去幾次廁所,一覺睡...
    Maymei6閱讀 248評論 0 6
  • (一)所謂善良翅敌,就是你明知道對方的痛點在哪里羞福,不管他如何對你,卻從不去碰觸蚯涮。 (二)等到有一天治专,不急不氣不惱了,那...
    吧啦吧啦咔咔咔閱讀 327評論 0 2