你必須要了解的幾種排序方法


  作為一個程序員,你怎么能不了解冒泡算法呢?

  下面向大家介紹六中排序算法,並提供javascript實現,以及簡單分析算法復雜度。

1. 簡單排序方法

1.1 冒泡排序

總體描述:
  相鄰元素進行比較,每次選取最大的元素,進行下一次比較,因此可以將最大的元素像冒泡一樣,從某一位置,到達最頂端
算法簡單描述:
  假設:共有n個元素
  進行(n-1)次循環,第i(從1開始計數)次循環獲得第i大的元素,放在數組第(n-i)(數組從0開始計數)位
每次循環都從第一個元素開始,比較當前元素與其后一個元素的大小關系,如果后一個元素小於當前元素,則說明,當前元素較大,互換位置,即將(0~n-i區間最大的數放在n-i位),並將當前元素指向下一個位置,直到當前位置指向0,循環結束

完整代碼:

function bubbleSort(originArr) {
    /* 數組副本 */
    var cloneArr = originArr.concat();
    /* 用於交換數據 */
    var temp;
    /* 數組長度 */
    var len = cloneArr.length;

    /* 每次選擇出最大的元素 */
    /* 通過比較相鄰元素,將較大的元素放在后面,將較大的數繼續進行比較 */
    for (var i = 0; i < len - 1; ++i) { // 需要執行len-1次 for (var j = 0; j < len - i; ++j) { // 需要執行len-i-1次 // 如果當前元素大於下一個元素,互換兩個元素 
            if (cloneArr[j] > cloneArr[j + 1]) { // 執行(1 + 2 + ... + n-1)算法復雜度為O(n^2)
                temp = cloneArr[j];
                cloneArr[j] = cloneArr[j + 1];
                cloneArr[j + 1] = temp;
            }
        }
    }

    return cloneArr;
}

1.2 選擇排序

總體描述:
  每次選擇最小的元素,放在相應的位置上
算法簡單描述:
  假設:共有n個元素
  進行(n-1)次循環,第i(從1開始計數)次循環獲得第i小的元素,放在數組第(i-1)(數組從0開始計數)位,第i次循環,從數組第(i-1)位開始,將該位置元素與其后所有元素進行比較,獲取較小元素索引,循環結束之后,將當前元素與最小索引位置元素位置互換,當前位置向前移動,進行下一輪循環,直到當前位置指向(n-1)

完整代碼:

function selectionSort(originArr) {
    /* 數組副本 */
    var cloneArr = originArr.concat();
    /* 用於交換數據 */
    var temp;
    /* 存放最小元素索引 */
    var minIndex = 0;
    /* 數組長度 */
    var len = cloneArr.length;

    /* 從第一個位置開始,比較當前位置和后面所有元素,獲取最小元素后面的位置 */
    for (var i = 0; i < len - 1; ++i) { // 需要執行len-1次
        minIndex = i;
        // 獲取最小元素位置 
        for (var j = i + 1; j < len; ++j) { // 需要執行len-i-1次
            if (cloneArr[minIndex] > cloneArr[j]) { // 執行(1 + 2 + ... + n-1)算法復雜度為O(n^2)
                minIndex = j;
            }
        }
        // 如果最小元素所在索引,不是當前位置,交換元素 
        if (minIndex !== i) {
            temp = cloneArr[i];
            cloneArr[i] = cloneArr[minIndex];
            cloneArr[minIndex] = temp;
        }
    }

    return cloneArr;
}

1.3 插入排序

總體描述:
  將數組分為前后兩部分,前一部分是已排序的元素集合,后一部分是未排序的元素集合。每次選中未排序的第一個數組,插入到已排序集合中的合適的位置
算法簡單描述:
  假設:共有n個元素
  從第2個元素開始,進行(n-1)次循環,第i次循環,將第i個元素插入到之前位置(1~i-1)中,將當前元素依次后面元素進行比較。比較元素起始值為當前元素前一位置元素,如果當前元素小於比較元素,比較元素向數組后面移動,當前元素繼續與下一個元素進行比較,直到比較元素位置為0或者當前元素大於比較元素,將元素插入當前比較位置

完整代碼:

function insertSort(originArr) {
    /* 數組副本 */
    var cloneArr = originArr.concat();
    /* 用於交換數據 */
    var temp;
    /* 數組長度 */
    var len = cloneArr.length;

    /* 循環數組中的每一個元素 */
    for (var i = 1; i < len; ++i) { // 需要執行len-1次
        // 記錄要插入的值 
        temp = cloneArr[i];
        // 找到合適的位置插入 
        for (var j = i - 1; j >= 0; --j) { // 需要執行i次
            if (temp < cloneArr[j]) { // 執行(1 + 2 + ... + n-1)算法復雜度為O(n^2)
                // 右移已排序數組 
                cloneArr[j + 1] = cloneArr[j];
            } else {
                break;
            }
        }
        cloneArr[j + 1] = temp;
    }

    return cloneArr;
}

2. 高級排序算法

2.1 希爾排序

總體描述:

  希爾排序就是插入排序的優化,插入排序,每次將當前元素與之前的每一個元素進行比較,然后插入,希爾排序,相當於先按照一定步長,將數組進行分組,對每一組進行插入排序,這樣就可以大幅度的調整數據的分布情況,最后執行一次快速排序進行微調
算法簡單描述:
  對於間隔數組中的每個元素gap,將數組元素根據gap分為gap組,對於每組進行插入排序

完整代碼:

function shellSort(originArr) {
    /* 數組副本 */
    var cloneArr = originArr.concat();
    /* 用於交換數據 */
    var temp;
    /* 數組長度 */
    var len = cloneArr.length;
    /* 間隔數組 */
    var gap = [];

    /* 動態創建間隔數組 */
    for (var i = Math.floor(len / 2); i > 0;) {
        gap.push(i);
        i = Math.floor(i / 2);
    }

    /* 使用間隔數組中的每一個元素,選擇數組中的元素,進行快速排序 */
    /* 方法1: 對每一個間隔的每一個分組進行快速排序 */
    /*for (var i = 0, gapLen = gap.length; i < gapLen; ++i) {
        // 分為gap[i]組分別進行排序 
        for (var j = 0; j < gap[i]; ++j) {
            // 第j組進行排序 
            for (var k = j + gap[i]; k < len; k = k + gap[i]) {
                temp = cloneArr[k];
                while (k - gap[i] >= 0 && cloneArr[k - gap[i]] > temp) {
                    cloneArr[k] = cloneArr[k - gap[i]];
                    k = k - gap[i];
                }
                cloneArr[k] = temp;
            }
        }
    }*/
    /* 方法2: 對於每一個間隔,從間隔位置開始,對其后每一個元素進行快速排序,保證前面的已經排好序 */
    for (var i = 0, gapLen = gap.length; i < gapLen; ++i) {
        for (var j = gap[i]; j < len; ++j) {
            temp = cloneArr[j];
            var k = j;
            while (k - gap[i] >= 0 && cloneArr[k - gap[i]] > temp) {
                cloneArr[k] = cloneArr[k - gap[i]]; 
                k -= gap[i];
            }
            cloneArr[k] = temp;
        }
    // 最壞情況O(n(logn)^2) 平均情況O(n(logn)^2) }
return cloneArr; }

2.2 快速排序

總體描述:
  每次選取一個基准值,將數組中其他的元素和它進行比較,大於則移到數組右邊,小於則移到左邊。然后分類出來的數組繼續進行上述操作。
算法簡單描述:
  選擇數組第一位元素位基准值,創建兩個新數組,分別存放小於基准值和大於基准值的元素。然后這兩個新數組遞歸進行上述操作,直到數組為空。然后將左右數組和基准值進行拼接

完整代碼:

function quickSort(originArr) {
    /* 如果數組為空,直接返回 */
    if (originArr.length === 0) {
        return [];
    }

    /* 基准值 */
    var pivot = originArr[0];
    /* 分別存放大於小於數組 */
    var lesser = [];
    var greater = [];

    /* 小於基准值,存放到lesser數組中,否則存放到greater數組中 */
    for (var i = 1; i < originArr.length; ++i) {
        if (originArr[i] < pivot) {
            lesser.push(originArr[i]);
        } else {
            greater.push(originArr[i]);
        }
    // 最壞情況O(n^2) 平均情況O(nlogn) }
/* 將數組拼接后返回 */ return quickSort(lesser).concat(pivot, quickSort(greater)); }

2.3 歸並排序

總體描述:
  自頂向下:先通過遞歸分解數組,再合並數組
算法簡單描述:
  分解數組:如果數組長度不為1,從中間將數組分為兩部分,繼續分解
  合並數組:將分解的數組融合,創建一個新數組,用於存放融合的數組元素。創建指針分別指向兩個數組的首位,比較當前指針指向位置元素的大小,將較小的元素插入新數組中,指針向后移動,直到有一個數組元素全部移出。最后檢查兩個數組,將未移出的元素追加到新數組中,最后存放已排序的數組根據對應位置存入待排序數組中

完整代碼:

function mergeSort(originArr) {
    /* 數組副本 */
    var cloneArr = originArr.concat();

    /* 調用歸並排序 */
    doMergeSort(cloneArr, 0, cloneArr.length - 1);

    return cloneArr;
}

/* 向下分解數組,遞歸調用 */
function doMergeSort(arr, low, high) {
    if (low < high) {
        var mid = low + Math.floor((high - low) / 2);
        doMergeSort(arr, low, mid);
        doMergeSort(arr, mid + 1, high);
        merge(arr, low, mid, high);
    // 最壞情況O(nlogn) 平均情況O(nlogn) } }
/* 數組融合 */ function merge(arr, low, mid, high) { var p_low = low; var p_high = mid + 1; var sortArr = []; /* 比較左右部分元素,將較小的元素存放在sortArr前面 */ while (p_low <= mid && p_high <= high) { if (arr[p_low] > arr[p_high]) { sortArr.push(arr[p_high++]); } else { sortArr.push(arr[p_low++]); } } /* 將兩部分可能剩余的元素復制到數組中 */ while (p_high <= high) { sortArr.push(arr[p_high++]); } while (p_low <= mid) { sortArr.push(arr[p_low++]); } /* 將已排序的數組復制到原數組對應位置 */ for (var i = low; i < high + 1; i++) { arr[i] = sortArr[i - low]; } }

3. 最終測試結果

100000數組測試:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM