算法基礎 --- 十大排序

排序算法導圖

概念

穩定:如果a原本在b前面,而a=b,排序之後a仍然在b的前面;
不穩定:如果a原本在b的前面,而a=b,排序之後a可能會出現在b的後面;
內排序:所有排序操作都在內存中完成;
外排序:由於數據太大,因此把數據放在磁盤中,而排序通過磁盤和內存的數據傳輸才能進行;
時間複雜度: 一個算法執行所耗費的時間。
空間複雜度: 運行完一個程序所需內存的大小

分類

複雜度

三大基礎排序

1.冒泡排序

1.比較相鄰的兩個元素,如果前一個比後一個大,則交換位置。
2.第一輪的時候最後一個元素應該是最大的一個。
3.按照步驟一的方法進行相鄰兩個元素的比較,這個時候由於最後一個元素已經是最大的了,所以最後一個元素不用比較。

 function bubbleSort(arr){
    var len = arr.length;
    for(let i=0;i<len-1;i++){
        for(let j=0;j<len-i-1;j++){
            if(arr[j] > arr[j+1]){
                swap(arr, j, j+1);
            }
        }
    }
 }

2.選擇排序

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,
然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到已排序序列的末尾。
以此類推,直到所有元素均排序完畢。

 function selectSort(arr){
    var len = arr.length;
    var minIndex;
    for(let i=0;i<len-1;i++){
        minIndex = i;
        for(let j=i+1;j<len;j++){
            if(arr[j] < arr[tmp]){
                minIndex = j;
            }
        }
        swap(arr, i, minIndex);
    }
 }

3.插入排序

從第一個元素開始,該元素可以認爲已經被排序
2.取出下一個元素,在已經排序的元素序列中從後向前掃描
3.如果該元素(已排序)大於新元素,將該元素移到下一位置
4.重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
5.將新元素插入到下一位置中
6.重複步驟2

 function insertSort(arr){
    for(let i=0;i<arr.length-1;i++){
        if(arr[i] > arr[i+1]){
            let minValue = arr[i+1];
            let index = i;
            while(index >= 0 && arr[index] > minValue){
                arr[index+1] = arr[index];
                index--;
            }
            arr[index+1] = minValue;
        }
    }
 }

四大進階排序

1.希爾排序

希爾排序是插入排序的一種更高效率的實現。它與插入排序的不同之處在於,它會優先比較距離較遠的元素。希爾排序的核心在於間隔序列的設定。既可以提前設定好間隔序列,也可以動態的定義間隔序列。

 function shellSort(arr) {
     var len = arr.length,
         temp,
         gap = 1;
     while(gap < len/3) {          //動態定義間隔序列
         gap =gap*3+1;
     }
     for (gap; gap> 0; gap = Math.floor(gap/3)) {
         for (var i = gap; i < len; i++) {
             temp = arr[i];
             for (var j = i-gap; j > 0 && arr[j]> temp; j-=gap) {
                 arr[j+gap] = arr[j];
             }
             arr[j+gap] = temp;
         }
     }
 }

2.歸併排序

歸併排序是建立在歸併操作的一種有效的排序算法,該算法是採用分治法的一個非常典型的應用。歸併排序是一種穩定的排序算法,將已有序的子序列合併,等到一個完全有序的序列,即先使每個子序列有序,再使子序列段有序,若將兩個有序表合併成一個有序表,稱作2路合併

function merge(left, right) {
  var tmp = [];
  while (left.length && right.length) {
      left[0] < right[0] ? tmp.push(left.shift()) : tmp.push(right.shift());
  }
  return tmp.concat(left, right);
}

function mergeSort(arr) {
  if (arr.length === 1) 
    return arr;
  var mid = Math.floor(arr.length / 2);
  var left = arr.slice(0, mid);
  var right = arr.slice(mid);
  return merge(mergeSort(left), mergeSort(right));
}

3.快速排序

快速排序的基本思想是:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序

function quickSort(arr){
    if(arr.length<=1){
        return arr;
    }
    let left = [];
    let right = [];
    let mark = arr.shift();
    for(let i=0;i<arr.length;i++){
        arr[i] < mark ? left.push(arr[i]) : right.push(arr[i]);
    }
    return quickSort(left).concat([mark], quickSort(right));
}

4.堆排序

將初始待排序關鍵字序列(R1,R2….Rn)構建成大頂堆,此堆爲初始的無序區;
將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,……Rn-1)和新的有序區(Rn),且滿足R[1,2…n-1]<=R[n];
由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,……Rn-1)調整爲新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2….Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數爲n-1,則整個排序過程完成。

function heapSort(array) {
    let length = array.length;
    buildMaxHeap(array);
    for (let j = length - 1; j >= 1; j--) {
        swap(array, 0, j);
        heap(array, 0, --length);
    }
}  

function buildMaxHeap(array){
    let length = array.length;
    for (let i = Math.ceil(length / 2) - 1; i >= 0; i--) {
        heap(array, i, length);
    }
}
function heap(array, x, length) {
    let l = 2 * x + 1, r = 2 * x + 2, largest = x;
    if (l < length && array[l] > array[largest]) {
        largest = l;
    }
    if (r < length && array[r] > array[largest]) {
        largest = r;
    }
    if (largest != x) {
        swap(array, x, largest);
        heap(array, largest, length);
    }
}

三大計數排序

1.計數排序

計數排序不是基於比較的排序算法,其核心在於將輸入的數據值轉化爲鍵存儲在額外開闢的數組空間中。 作爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有確定範圍的整數。

function countingSort(arr) {
    var maxValue = getMaxValue(arr);
    var bucket =new Array(maxValue + 1),
        sortedIndex = 0;
        arrLen = arr.length,
        bucketLen = maxValue + 1;
    for (var i = 0; i < arrLen; i++) {
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }
    for (var j = 0; j < bucketLen; j++) {
        while(bucket[j] > 0) {
            arr[sortedIndex++] = j;
            bucket[j]--;
        }

    }
}

function getMaxValue(arr){
    let maxValue = arr[0];
    for(let i=1;i<arr.length;i++){
        if(arr[i] > maxValue){
            maxValue = arr[i];
        }
    }
    return maxValue;
}

2.桶排序

桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的確定。桶排序 (Bucket sort)的工作的原理:假設輸入數據服從均勻分佈,將數據分到有限數量的桶裏,每個桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排)

function bucketSort(arr) {

    let tmp = [];
    let counts = 5; //每個桶5個數
    let minValue = arr[0];
    let maxValue = arr[0];

    for(let i=0;i<arr.length;i++){
        (arr[i] < minValue) && (minValue = arr[i]);
        (arr[i] > maxValue) && (maxValue = arr[i]);
    }

    for(let i=0;i<arr.length;i++){
        let index = Math.floor((arr[i]-minValue)/counts);
        tmp[index] || (tmp[index] = []); 
        tmp[index].push(arr[i]);
    }
    arr.length = 0;
    for(let i=0;i<tmp.length;i++){
        if(tmp[i]){
            insertSort(tmp[i]);
            arr = arr.concat(tmp[i]);
        }
    }
    return arr;
}

3.基數排序

基數排序是按照低位先排序,然後收集;再按照高位排序,然後再收集;依次類推,直到最高位。有時候有些屬性是有優先級順序的,先按低優先級排序,再按高優先級排序。最後的次序就是高優先級高的在前,高優先級相同的低優先級高的在前

function radixSort(arr, maxDigit) {
    var counter = [];
    var mod = 10;
    var dev = 1;
    for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for(var j = 0; j < arr.length; j++) {
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]==null) {
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
            var value =null;
            if(counter[j]!=null) {
                while ((value = counter[j].shift()) !=null) {
                      arr[pos++] = value;
                }
          }
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章