常見排序算法JavaScript實現(xiàn)

排序算法穩(wěn)定性

假定在待排序的記錄序列中类嗤,存在多個具有相同的關鍵字的記錄罕容,若經(jīng)過排序,這些記錄的相對次序保持不變,即在原序列中仇轻,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前辉川,則稱這種排序算法是穩(wěn)定的;否則稱為不穩(wěn)定的拴测。

Array.prototype.sort

js標準庫中的排序方法乓旗,可傳入一個函數(shù)自定義比較規(guī)則。流行的瀏覽器實現(xiàn)都是穩(wěn)定的排序算法集索。(例如chrome之前使用的是快排屿愚,在7.0版本之后換成了Timsort

關于Array.prototype.sort()詳細介紹見 MDN。

冒泡排序

最蠢的排序务荆。遍歷數(shù)組妆距,依次對比相鄰的兩個數(shù),如果兩個數(shù)的順序錯誤則交換位置函匕。平均時間復雜度為 O(n2)娱据,穩(wěn)定排序。


冒泡.png
function Bubble (arr){
        if (!arr || !arr.length )  return arr;

        for (let i = arr.length; i > 0; i--) {
            for (let j = 1; j < i; j++) {
                if (arr[j] < arr[j - 1]) {
                    const tem = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = tem;
                }
            }
        }
        return arr;
}

雞尾酒排序

冒泡排序改良版盅惜,又稱雙向冒泡排序中剩。在每一輪遍歷中,進行兩次冒泡抒寂。一次將最大值置于一端结啼,一次將最小值置于另一端。性能略為優(yōu)化蓬推,平均時間復雜度仍然是 O(n2)妆棒。穩(wěn)定排序。


雞尾酒排序.png
function Cocktail(arr) {
        if (!arr || !arr.length )  return arr;

        for (let i = arr.length; i > 0; i--) {
            for (let j = i - 1; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {
                    const tem = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = tem;
                }
            }

            for (let j = arr.length - i + 1; j < i; j++) {
                if (arr[j] < arr[j - 1]) {
                    const tem = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = tem;
                }
            }
        }
        return arr;
}

插入排序

類似打撲克將牌排序的手法沸伏,外層循環(huán)從第一個元素開始遍歷糕珊,內層循環(huán)將下一個元素與左側元素依次比較,插入到應處的位置毅糟。因為進行內層循環(huán)時红选,元素位置對的情況下無需繼續(xù)進行遍歷,所以效率比冒泡高很多姆另。特別是在數(shù)組大部分元素有序情況下效率很高喇肋。但在極端情況下依然需要進行完全遍歷,所以平均時間復雜度也還是O(n2)迹辐。穩(wěn)定排序蝶防。


插入排序.png
function Insertion (arr){
        for (let i = 0; i < arr.length; i++) {
            for (let j = i + 1; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {
                    const tem = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = tem;
                }else{
                    break;
                }
            }
        }
        return arr;
}

選擇排序

外層循環(huán)依次遍歷數(shù)組,內層循環(huán)遍歷未排序部分找出最小/大的元素與前面的元素交換明吩。與插入排序比較间学,選擇排序無需進行頻繁的元素交換動作,內層循環(huán)只是標記最小元素,遍歷完成后進行一次交換低葫。減少了交換的開銷详羡。但選擇排序無論如何都需要完全遍歷數(shù)組,在大部分有序情況下效率低于插入排序嘿悬。平均時間復雜度也還是O(n2)实柠。不穩(wěn)定排序。


選擇排序.png
class Selection(arr){
        for (let i = 0; i < arr.length; i++) {
            let min = arr[i];
            let minIndex = i;
            for (let j = i; j < arr.length; j++) {
                if (arr[j] < min) {
                    min = arr[j];
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                let tem = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = tem;
            }
        }
        return arr;
}

希爾排序

to be continued

歸并排序

歸并排序一種基于分治法思路的排序善涨。通過將數(shù)組兩兩劃分窒盐,排序后再合并。平均時間復雜度為O(nlogn)躯概,需要申請空間進行合并操作登钥,空間復雜度為T(n)。是一種穩(wěn)定的排序算法娶靡。穩(wěn)定排序牧牢。


歸并排序.png
function Merge(arr) {
    if (arr.length <= 1) {
        return arr;
    }

    const mid = Math.floor(arr.length / 2);
    const left = arr.slice(0, mid);
    const right = arr.slice(mid);

    return sort(Merge(left), Merge(right));
}

function sort(arrA, arrB) {
    let i = 0;
    let j = 0;
    const arr = [];
    while (arrA.length > 0 && arrB.length > 0) {
        if (arrA[0] < arrB[0]) {
            arr.push(arrA.shift());
        } else {
            arr.push(arrB.shift());
        }

        if (arrA.length == 0) {
            arr = arr.concat(arrB);
        } else if (arrB.length == 0) {
            arr = arr.concat(arrA);
        }
    }

    return arr;
}

快速排序

最快的排序算法。思路是先取一個基準值姿锭,然后雙指針遍歷數(shù)組塔鳍。右指針負責找到比基準值小的值,左指針負責找到比基準值大的值呻此,兩值交換轮纫。使得數(shù)組一邊是比基準值小的,一邊是比基準值大的焚鲜。然后再分別對這兩邊進行排序掌唾。平均時間復雜度為O(nlogn),不穩(wěn)定排序忿磅∨幢颍快的原理是通過雙指針,使得每一輪循環(huán)可以使多個元素大致歸位葱她。

快速排序.png

快排遞歸版本

    function QuickSortRecursion(arr) {
        partition(arr, 0, arr.length - 1);
        return arr;
    }
    function partition(arr, start, end) {
        if (arr.length <= 1 || start === end) {
            return;
        }
        let left = start, right = end;
        let key = arr[start];

        while(left < right){

            while(left < right &&  key <= arr[right]){//右指針往左走撩扒,尋找比基準值小的值
                right--;
            }

            while(left < right && key >= arr[left]){//左指針向右走,尋找比基準值大的值
                left++;
            }

            //交換元素
            const tem = arr[right];
            arr[right] = arr[left];
            arr[left] = tem;

        }
        
        if(left == right && key > arr[right]){//如果指針所指比基準值小
            arr[start] = arr[right];
            arr[right] = key;
        }

        if(left - 1 > start){
            partition(arr, start, left - 1);
        }

        if(right + 1 < end){
            partition(arr, right + 1, end);
        }
    }

非遞歸版本
似乎遞歸的算法變不遞歸都是利用棧來解決的吨些。其實遞歸也就是函數(shù)調用棧搓谆,原理是完全一樣的。但函數(shù)調用棧里保存了每一個函數(shù)的執(zhí)行上下文豪墅,占用內存會比循環(huán)+棧的方式大得多泉手,當多重嵌套時會導致爆棧。改為循環(huán)+棧的形式可以處理更大的數(shù)組偶器。

function QuickSort(arr){
    const stack = [];
    let start = 0, end = arr.length - 1;
    do {
        let indexData = null;
        if (stack.length != 0) {
            let data = stack.pop();
            start = data.start;
            end = data.end;
        }

        indexData = this.partition(arr, start, end);

        if (indexData != null) {
            if (indexData - 1 > start) {
                stack.push({ start: start, end: indexData - 1 });
            }
            if (indexData + 1 < end) {
                stack.push({ start: indexData + 1, end: end });
            }
        }
    } while (stack.length != 0);
    return arr;
}

function partition(arr, start, end) {
    if (arr.length <= 1 || start === end) {
        return null;
    }
    let left = start, right = end;
    let key = arr[start];

    while(left < right){

        while(left < right &&  key <= arr[right]){//右指針往左走螃诅,尋找比基準值小的值
            right--;
        }

        while(left < right && key >= arr[left]){//左指針向右走啡氢,尋找比基準值大的值
            left++;
        }

        const tem = arr[right];
        arr[right] = arr[left];
        arr[left] = tem;//交換元素

    }
    
    if(left == right && key > arr[right]){//如果指針所指比基準值小
        arr[start] = arr[right];
        arr[right] = key;
    }

    return left;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市术裸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亭枷,老刑警劉巖袭艺,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異叨粘,居然都是意外死亡猾编,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門升敲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來答倡,“玉大人,你說我怎么就攤上這事驴党”衿玻” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵港庄,是天一觀的道長倔既。 經(jīng)常有香客問我,道長鹏氧,這世上最難降的妖魔是什么渤涌? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮把还,結果婚禮上实蓬,老公的妹妹穿的比我還像新娘。我一直安慰自己吊履,他們只是感情好安皱,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著率翅,像睡著了一般练俐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冕臭,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天腺晾,我揣著相機與錄音,去河邊找鬼辜贵。 笑死悯蝉,一個胖子當著我的面吹牛,可吹牛的內容都是我干的托慨。 我是一名探鬼主播鼻由,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蕉世?” 一聲冷哼從身側響起蔼紧,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狠轻,沒想到半個月后奸例,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡向楼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年查吊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湖蜕。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡逻卖,死狀恐怖,靈堂內的尸體忽然破棺而出昭抒,到底是詐尸還是另有隱情评也,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布戈鲁,位于F島的核電站仇参,受9級特大地震影響,放射性物質發(fā)生泄漏婆殿。R本人自食惡果不足惜诈乒,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望婆芦。 院中可真熱鬧怕磨,春花似錦、人聲如沸消约。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽或粮。三九已至导饲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氯材,已是汗流浹背渣锦。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氢哮,地道東北人袋毙。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像冗尤,于是被迫代替她去往敵國和親听盖。 傳聞我的和親對象是個殘疾皇子胀溺,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350