排序

常見的八種排序算法


排序算法結(jié)構(gòu)圖

各種排序算法的比較

不穩(wěn)定:快選堆希
穩(wěn) 定:插冒歸基


直接插入排序:

算法思想:
將數(shù)組中所有的元素與前面已經(jīng)排好序的元素進(jìn)行比較,如果選擇的元素比已排序的元素小割粮,則交換
使用兩個循環(huán)完成
第一層循環(huán):遍歷待比較的所有元素
第二層循環(huán):將本輪選擇的元素與已經(jīng)排好序的元素相比較,如果選擇的元素比已排序的元素小,則交換

  • 時間復(fù)雜度:
    平均情況:O(n2)
    最好情況:O(n) 已排好序的數(shù)列
    最壞情況:O(n2) 逆序的數(shù)列
  • 空間復(fù)雜度:O(1)
  • 穩(wěn)定性:穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j > -1; j-- ) {
        if (arr[j] < arr[j - 1]) {
            var t = arr[j];
            arr[j] = arr[j - 1];
            arr[j - 1] = t;
        }
    }
}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


希爾排序

算法思想:
將數(shù)組按下標(biāo)進(jìn)行一定增量的分組拳球,對每組使用插入算法排序,隨著增量的減少珍特,每組包含的數(shù)據(jù)會越來越多祝峻,當(dāng)增量為1時,整個數(shù)組都被分到一組,算法即終止莱找。

  • gap(增量):length / 2 酬姆,而后依次以gap = gap / 2,所以增量序列為{length / 2, (length / 2) / 2, ..., 1}
    注意: 希爾排序的增量序列的選擇與證明是個數(shù)學(xué)難題奥溺,我們選擇的這個增量序列是比較常用的辞色,也是希爾建議的增量,稱為希爾增量浮定,但其實(shí)這個增量序列不是最優(yōu)的相满。此處我們做示例使用希爾增量。
  • 時間復(fù)雜度:
    平均情況:O(n2)
    最好情況:O(n)
    最壞情況:O(n2)
  • 空間復(fù)雜度:O(1)
  • 穩(wěn)定性:不穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var gap = Math.floor(arr.length / 2); gap >= 1; gap = Math.floor(gap / 2)) {
    console.log('gap = ', gap);    //gap =  4, gap = 2, gap = 1
    for (var i = gap; i < arr.length; i++) {
        for (var j = i; j >= 0; j -= gap) {
            if (arr[j] < arr[j - gap]) {
                var t = arr[j];
                arr[j] = arr[j - gap];
                arr[j - gap] = t;
            }
        }
    }

}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


簡單排序

算法思想:

  1. 從待排序的序列中桦卒,找到最小的元素立美;
  2. 如果最小元素不是第一個,將把最小元素與第一個交換方灾,將余下的元素置為待排序元素建蹄,重復(fù)1,2步驟,直到待排序元素為1裕偿。
  • 時間復(fù)雜度:
    平均情況:O(n2)
    最好情況:O(n2)
    最壞情況:O(n2)
  • 空間復(fù)雜度:O(1)
  • 穩(wěn)定性:不穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j < arr.length; j++) {
        if (arr[j] < arr[i]) {
            var t = arr[j];
            arr[j] = arr[i];
            arr[i] = t;
        }
    }
}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 8, 7, 9 ]


堆排序

算法思想:

  1. 將待排序序列構(gòu)造成一個大頂堆(小頂堆)洞慎,堆頂?shù)母?jié)點(diǎn)就是整個序列最大值(最小值);
  2. 然后將其與末尾元素進(jìn)行交換击费,此時末尾元素就是最大值(最小值)了拢蛋;
  3. 將剩余的元素構(gòu)造成一個堆,重復(fù)1,2,3步驟蔫巩,直到剩余的元素為1谆棱。

注:
堆:堆是滿足大頂堆或小頂堆的完全二叉樹
大頂堆:每個結(jié)點(diǎn)的值都大于或等于其左右孩子結(jié)點(diǎn)的值
小頂堆:每個結(jié)點(diǎn)的值都小于或等于其左右孩子結(jié)點(diǎn)的值

  • 時間復(fù)雜度:
    平均情況:O(nlog2n)
    最好情況:O(nlog2n)
    最壞情況:O(nlog2n)
  • 空間復(fù)雜度:O(1)
  • 穩(wěn)定性:不穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function ajustArr(arr, i, length) {
    for (var j = i * 2 + 1; j < length; j = j * 2 + 1) {
        if ((j + 1 < length) && (arr[j] < arr[j + 1])) {
            j++;
        }

        if (arr[j] > arr[i]) {
            var t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
            i = j;
        }

    }
}

function makeHeap(arr, n) {
    for (var i = Math.floor(n / 2 - 1); i >= 0; i--) {
        ajustArr(arr, i, n);
    }
}

function heapSort(arr) {
    makeHeap(arr, arr.length);
    for (var i = arr.length - 1; i >= 0; i--) {
        
        console.log(arr);   
        // [ 9, 8, 6, 7, 5, 1, 4, 2, 3 ]
        // [ 8, 7, 6, 3, 5, 1, 4, 2, 9 ]
        // [ 7, 5, 6, 3, 2, 1, 4, 8, 9 ]
        // [ 6, 5, 4, 3, 2, 1, 7, 8, 9 ]
        // [ 5, 3, 4, 1, 2, 6, 7, 8, 9 ]
        // [ 4, 3, 2, 1, 5, 6, 7, 8, 9 ]
        // [ 3, 1, 2, 4, 5, 6, 7, 8, 9 ]
        // [ 2, 1, 3, 4, 5, 6, 7, 8, 9 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

        var t = arr[i];
        arr[i] = arr[0];
        arr[0] = t;
        ajustArr(arr, 0, i);
    }
}

heapSort(arr);

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


冒泡排序

算法思想:

  1. 將序列中的左右元素進(jìn)行比較,保證右邊的元素始終大于(小于)左邊的元素圆仔;
  2. 循環(huán)執(zhí)行步驟1垃瞧,執(zhí)行完成后,序列的最后一個元素即為當(dāng)前序列的最大值(最小值)坪郭;
  3. 對剩余的元素循環(huán)執(zhí)行步驟1,2个从,直到剩余的元素為1。
  • 時間復(fù)雜度:
    平均情況:O(n2)
    最好情況:O(n)
    最壞情況:O(n2)
  • 空間復(fù)雜度:O(1)
  • 穩(wěn)定性:穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j < arr.length; j++) {
        if (arr[j] > arr[j + 1]) {
            var t = arr[j + 1];
            arr[j + 1] = arr[j];
            arr[j] = t;
        }
    }
}
console.log(arr);   //[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


快速排序 (分治)

算法思想:

  1. 在列表中選擇一個基準(zhǔn)數(shù)(pivot)
  2. 將序列當(dāng)中的所有數(shù)依次遍歷歪沃,比基準(zhǔn)數(shù)大的位于其右側(cè)嗦锐,比基準(zhǔn)數(shù)小的位于其左側(cè)
  3. 重復(fù)步驟1,2,直到所有子集當(dāng)中只有一個元素為止沪曙。
  • 時間復(fù)雜度:
    平均情況:O(nlog2n)
    最好情況:O(nlog2n)
    最壞情況:O(n2)
  • 空間復(fù)雜度:O(nlog2n)
  • 穩(wěn)定性:不穩(wěn)定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function quickSort(arr, start, end) {
    if (start < end) {
        var pivot = arr[start];
        var left = start;
        var right = end;

        while(left < right) {
            while((left < right) && (pivot <= arr[right]))  right--;
            if (left < right) {
                arr[left] = arr[right];
                left++;
            }
            while((left < right) && (pivot >= arr[left]))  left++;
            if (left < right) {
                arr[right] = arr[left];
                right--;
            }
        }

        arr[left] = pivot;
        console.log(arr);   
        // [ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

        quickSort(arr, left + 1, end);
        quickSort(arr, start, left - 1);
    }
}
quickSort(arr, 0, arr.length - 1);

console.log(arr);   //[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


歸并排序(分治)

建立在歸并操作上的排序算法奕污,是分治法的典型應(yīng)用。

算法思想:
將數(shù)據(jù)分為兩組液走,如果組內(nèi)數(shù)據(jù)只有一個時碳默,認(rèn)為組內(nèi)數(shù)據(jù)有序贾陷,然后進(jìn)行合并相鄰的兩組數(shù)據(jù)即可

  • 如何將兩個有序數(shù)列合并?
    比較兩個數(shù)列的第一個數(shù)嘱根,誰小就先取誰髓废,取了后就在對應(yīng)數(shù)列中刪除這個數(shù),然后再進(jìn)行比較该抒,如果數(shù)列為空慌洪,那就直接將另一個數(shù)列的數(shù)據(jù)依次取出。

  • 時間復(fù)雜度:
    平均情況:O(nlog2n)
    最好情況:O(nlog2n)
    最壞情況:O(nlog2n)

  • 空間復(fù)雜度:O(1)

  • 穩(wěn)定性:穩(wěn)定

var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function mergeArr(arr, start, mid, end) {
    var tem = [], k = 0, i = start, j = mid + 1;
    while((i <= mid) && (j <= end)) {
        if (arr[i] <= arr[j]) {
            tem[k++] = arr[i++];
        } else {
            tem[k++] = arr[j++];
        }
    }

    while(i <= mid) {
        tem[k++] = arr[i++];
    }

    while(j <= end) {
        tem[k++] = arr[j++];
    }

    console.log('tem:', tem);
    // tem: [ 1, 3 ]
    // tem: [ 1, 3, 4 ]
    // tem: [ 2, 5 ]
    // tem: [ 1, 2, 3, 4, 5 ]
    // tem: [ 6, 9 ]
    // tem: [ 7, 8 ]
    // tem: [ 6, 7, 8, 9 ]
    // tem: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

    for (var i = 0; i < k; i++) {
        arr[start + i] = tem[i];
    }
}

function mergeSort(arr, start, end) {
    if (start < end) {
        var mid = Math.floor((start + end) / 2);
        mergeSort(arr, start, mid);
        mergeSort(arr, mid + 1, end);
        mergeArr(arr, start, mid, end);
    }
}

mergeSort(arr, 0, arr.length - 1);

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柔逼,一起剝皮案震驚了整個濱河市蒋譬,隨后出現(xiàn)的幾起案子割岛,更是在濱河造成了極大的恐慌愉适,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件癣漆,死亡現(xiàn)場離奇詭異维咸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)惠爽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門癌蓖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人婚肆,你說我怎么就攤上這事租副。” “怎么了较性?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵用僧,是天一觀的道長。 經(jīng)常有香客問我赞咙,道長责循,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任攀操,我火速辦了婚禮院仿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘速和。我一直安慰自己歹垫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布颠放。 她就那樣靜靜地躺著排惨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慈迈。 梳的紋絲不亂的頭發(fā)上若贮,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天省有,我揣著相機(jī)與錄音,去河邊找鬼谴麦。 笑死蠢沿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匾效。 我是一名探鬼主播舷蟀,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼面哼!你這毒婦竟也來了野宜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤魔策,失蹤者是張志新(化名)和其女友劉穎匈子,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闯袒,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虎敦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了政敢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片其徙。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖喷户,靈堂內(nèi)的尸體忽然破棺而出唾那,到底是詐尸還是另有隱情,我是刑警寧澤褪尝,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布闹获,位于F島的核電站,受9級特大地震影響恼五,放射性物質(zhì)發(fā)生泄漏昌罩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一灾馒、第九天 我趴在偏房一處隱蔽的房頂上張望茎用。 院中可真熱鬧,春花似錦睬罗、人聲如沸轨功。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽古涧。三九已至,卻和暖如春花盐,著一層夾襖步出監(jiān)牢的瞬間羡滑,已是汗流浹背菇爪。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柒昏,地道東北人凳宙。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像职祷,于是被迫代替她去往敵國和親氏涩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

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