數據結構與算法-學習筆記(七)

排序

如何分析一個「排序算法」

  1. 排序算法的執行效率
  • 最好、最壞、平均狀況時間複雜度:爲甚要區分這三種時間複雜度?第一,有些排序算法會區分。第二,對於要排序的數據,有的接近有序、有的徹底無序。有序度不一樣的數據,對於排序的執行時間確定有影響,咱們要知道排序算法在不一樣數據下的性能表現。
  • 時間複雜度的係數、常數、低階:由於實際排序中數據規模可能比較小10個、100個這樣的,因此把係數、常數、低階也考慮進來更加準確。
  • 比較次數和交換(或移動)次數:若是是基於比較的排序算法。執行過程當中涉及兩種操做:1.元素比較大小;2.交換或移動。所以,在分析排序算法的執行效率時還要考慮次數。
  1. 排序算法的內存消耗
  • 空間複雜度
  • 新概念:原地排序(特指空間複雜度爲O(1))的排序算法。
  1. 排序算法的穩定性:指若是待排序的序列中存在值相等的元素,通過排序以後,相等元素之間原有的前後順序不變。那麼爲何要穩定性呢?由於真實排序是對真實對象可能經過某個屬性來排序,這時可能同時要求其餘屬性也是有序的,以下訂單按金額排序,相同金額按時間排序:
    這時保持本來順序不變就變得重要了。

具體排序算法

冒泡排序

思路:比較和交換。每次把當前未排序的數據中最大的數據找出,放在最後。往水裏扔個大石頭,石頭下沉,比石頭輕的氣泡上升。算法

function bubbleSort(array) {
    var length = array.length;
    for (let j = length; j > 1; j--) {
        let exchange = false;
        for (let i = 0; i < j-1; i++) {
            if (array[i] > array[i+1]) {
                let temp = array[i];
                array[i] = array[i+1];
                array[i+1] = temp;
                exchange = true;
            }
        }
        if (!exchange) return;
        
     }
}
複製代碼

對於平均複雜度,粗略的計算:

冒泡排序包含兩個操做:比較和交換。交換次數最好狀況=0;最差狀況=n*(n-1)/2,平均交換次數粗略來看是n*(n-1)/4,比較次數確定比交換次數多,所以在加上比較次數,因此平均複雜度大體是O(n2)。數組

插入排序

思路:比較和插入性能優化

將數組分爲兩個區域:已排序區域和未排序區域。主要操做已排序區域,最初就是數組第一個元素時有序,其他無序;每次從無序區域拿一個元素和前面有序區域元素比較,再插入合適位置。bash

function insertSort(array) {
    for (let i = 1; i < array.length; i++) {
        let currentValue = array[i];
        let j = i-1;
        for (; j >= 0 ; j--) {
            if (array[j] > currentValue) {
                array[j+1] = array[j];
            } else {
                break;
            }
        }
        array[j+1] = currentValue;
    }
}
複製代碼

最好的時間複雜度是徹底有序:O(n)性能

最壞的時間複雜度徹底逆序:O(n2)優化

平均時間複雜度:向數組插入一個元素的平均複雜度是O(n),而插入排序算法每一個元素都須要插入一次,所以是O(n2)ui

選擇排序

思路:查找和交換。同插入相似,分出已排序和未排序區間。可是選擇排序主要操做未排序區域,每次從未排序區間找出最小元素,將其放在已排序區間的末尾。spa

function selectSort(array) {
    for (let i = 0; i < array.length; i++) {
        let currentMinnum = array[i];
        let currentMinnumIndex = i;
        for (let j = i + 1; j < array.length; j++) {
            if (currentMinnum > array[j]) {
                currentMinnum = array[j];
                currentMinnumIndex = j;
            } 
        }
        let temp = array[currentMinnumIndex];
        array[currentMinnumIndex] = array[i];
        array[i] = temp;  
    }
}
複製代碼

能夠看出不管哪一種數據排序,時間複雜度都是同樣的O(n2);3d

以上三種排序比較

冒泡和插入排序時間複雜度、空間複雜度、穩定性都是同樣的,可是爲何說插入要比冒泡更好呢?主要是冒泡每次循環執行交換操做是3步,而插入僅是一步移動。所以當數據量比較大時,且但願把性能優化到極致的話,首選插入排序。code

若是數據結果變爲鏈表呢?

是否容許修改鏈表的節點value值,仍是隻能改變節點的位置。通常而言,考慮只能改變節點位置,冒泡排序相比於數組實現,比較次數一致,但交換時操做更復雜;插入排序,比較次數一致,不須要再有後移操做,找到位置後能夠直接插入,但排序完畢後可能須要倒置鏈表;選擇排序比較次數一致,交換操做一樣比較麻煩。綜上,時間複雜度和空間複雜度並沒有明顯變化,若追求極致性能,冒泡排序的時間複雜度係數會變大,插入排序係數會減少,選擇排序無明顯變化。

相關文章
相關標籤/搜索