圖解JavaScript算法排序

1、冒泡排序

算法介紹:javascript

  1. 比較相鄰的兩個元素,若是前一個比後一個大,則交換位置。
  2. 第一輪把最大的元素放到了最後面。
  3. 因爲每次排序最後一個都是最大的,因此以後按照步驟1排序最後一個元素不用比較。
function bubble_sort(arr){
  var swap;  
  for(var i=0;i<arr.length-1;i++){
    for(var j=0;j<arr.length-i-1;j++){
      if(arr[j]>arr[j+1]){
        swap=arr[j];
        arr[j]=arr[j+1];
        arr[j+1]=swap;
      }
    }
  }
}
複製代碼

冒泡算法改進:html

  1. 設置一個標誌,若是這一趟發生了交換,則爲true。不然爲false。若是這一趟沒有發生交換,則說明排序已經完成。代碼以下:
function bubble_sort_1(arr) {
  var n = arr.length,
  flag = true,
  swap;
  while(flag){
    flag = false;
    for(var j = 1; j<n; j++){
      if(arr[j - 1]>arr[j]) {
        swap = arr[j-1];
        arr[j-1] = arr[j];
        arr[j] = swap;
       flag = true;
      }0
    }
    n --;  
  }
  return arr;
}
複製代碼
  1. 假如數組長度是20,若是隻有前十位是無序排列的,後十位是有序且都大於前十位,因此第一趟遍歷排序的時候發生交換的位置一定小於10,且該位置以後的一定有序,咱們只須要排序好該位置以前的就能夠,所以咱們要來標記這個位置就能夠了,便可以記錄每次掃描中最後一次交換的位置,下次掃描的時候只要掃描到上次的最後交換位置就好了,由於後面的都是已經排好序的,無需再比較,代碼以下:
function bubble_sort_2(arr) {
  var n=arr.length;
  var j,k;  
  var flag=n;
  var swap;
  while(flag>0) {  
    k=flag;  
    flag=0;  
    for(j=1;j<k;j++){ 
        if (arr[j - 1] > arr[j])  
        {  
            swap=arr[j-1];
            arr[j-1]=arr[j];
            arr[j]=swap;
            flag=j;  
        }  
    }  
  } 

}
複製代碼
  1. 每一次循環從兩頭出發算出最大和最小值,代碼以下:
function bubble_sort_3(arr) {&emsp;&emsp;
        var low = 0;
        var high = arr.length - 1; //設置變量的初始值
        var swap, j;
        while (low < high) {
            for (j = low; j < high; ++j) { //正向冒泡,找到最大者
                if (arr[j] > arr[j + 1]) {
                    swap = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = swap;
                }
            }&emsp;&emsp;&emsp;&emsp;--high; //修改high值, 前移一位
            for (j = high; j > low; --j) { //反向冒泡,找到最小者
                if (arr[j] < arr[j - 1]) {
                    swap = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = swap;
                }
            }
            ++low; //修改low值,後移一位
        }
        return arr;
    }
複製代碼
  1. 在代碼3的基礎上記錄每次掃描最後一次交換的位置,下次掃描的時候只要掃描到上次的最後交換位置就行,同代碼2,代碼以下:
function bubble_sort_3(arr) {&emsp;&emsp;
        var low = 0;
        var high = arr.length - 1; //設置變量的初始值
        var swap, j;
        while (low < high) {
            var pos1 = 0,
                pos2 = 0;
            for (let i = low; i < high; ++i) { //正向冒泡,找到最大者
                if (arr[i] > arr[i + 1]) {
                    swap = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = swap;
                    pos1 = i;
                }
            }
            high = pos1; // 記錄上次位置
            for (let j = high; j > low; --j) { //反向冒泡,找到最小者
                if (arr[j] < arr[j - 1]) {
                    swap = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = swap;
                    pos2 = j;
                }
            }
            low = pos2; //修改low值
        }
        return arr;
    }
複製代碼

冒泡排序動圖演示:java

2、快速排序

算法介紹:git

快速排序是對冒泡排序的一種改進,第一趟排序時將數據分紅兩部分,一部分比另外一部分的全部數據都要小。而後遞歸調用,在兩邊都實行快速排序。算法

function quick_sort(arr){
  if(arr.length<=1){
    return arr;
  }
  var pivotIndex=Math.floor(arr.length/2);
  var pivot=arr.splice(pivotIndex,1)[0];

  var left=[];
  var right=[];
  for(var i=0;i<arr.length;i++){
    if(arr[i]<pivot){
      left.push(arr[i]);
    }else{
      right.push(arr[i]);
    }
  }

  return quick_sort(left).concat([pivot],quick_sort(right));
}
複製代碼

快速排序動圖演示: shell

3、選擇排序

算法介紹:api

選擇排序就是從一個未知數據空間裏,選取之最放到一個新的空間數組

代碼以下:函數

function selection_sort(arr) {
        var len = arr.length;
        var minIndex, swap;
        for (var i = 0; i < len - 1; i++) {
            minIndex = i;
            for (var j = i + 1; j < len; j++) {
                if (arr[j] < arr[minIndex]) { //尋找最小的數
                    minIndex = j; //將最小數的索引保存
                }
            }
            swap = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = swap;
        }
        return arr;
    }
複製代碼

選擇排序動圖演示: 性能

4、插入排序

算法介紹:

  1. 從第一個默認被排好序的元素開始
  2. 取出下一個元素,在已經排序的元素序列中從後向前掃描
  3. 若是已排序的元素大於取出的元素,則將其分別向後移動一位
  4. 直到找到已排序的元素中小於或等於取出的元素,將取出的元素放到它的後一位
  5. 重複步驟2

代碼以下:

function insertion_sort(arr) {
        for (var i = 1; i < arr.length; i++) {
            var key = arr[i];
            var j = i - 1;
            while (arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
        return arr;
    }
複製代碼

插入排序算法改進-二分法插入排序:

function binaryInsertion_sort(arr) {
        for (var i = 1; i < arr.length; i++) {
            var key = arr[i],
                left = 0,
                right = i - 1;
            while (left <= right) {
                var middle = parseInt((left + right) / 2);
                if (key < arr[middle]) {
                    right = middle - 1;
                } else {
                    left = middle + 1;
                }
            }
            for (var j = i - 1; j >= left; j--) {
                arr[j + 1] = arr[j];
            }
            arr[left] = key;
        }
        return arr;
    }
複製代碼

插入排序法動圖演示:

5、希爾排序

算法介紹:

希爾排序是冒泡排序的一種更高效率的實現。它與冒泡排序的不一樣之處在於,它會優先比較距離較遠的元素。希爾排序的核心在於間隔序列的設定。

上圖中先每差5爲一組進行比較,以後再每差2爲一組驚醒比較,最後就是兩兩比較。代碼以下:

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

6、歸併排序

算法介紹:

做爲一種典型的分而治之思想的算法應用,歸併排序的實現由兩種方法:

  • 自上而下的遞歸(全部遞歸的方法均可以用迭代重寫,因此就有了第2種方法)
  • 自下而上的迭代

代碼以下:

function merge_sort(arr) {  //採用自上而下的遞歸方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
    var result = [];
 
    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }
 
    while (left.length)
        result.push(left.shift());
 
    while (right.length)
        result.push(right.shift());
 
    return result;
}
複製代碼

歸併排序動圖演示 :

7、堆排序

首先明白什麼是堆,堆其實能夠這麼理解,相似金字塔,一層有一個元素,兩層有兩個元素,三層有四個元素,每層從數組中取元素,從左到右的順序放到堆相應的位置上,也就是說每一層元素個數爲2n-1 ;(n 表明行數),這就完成了建堆。

堆排序能夠說是一種利用堆的概念來排序的選擇排序。分爲兩種方法:

  • 大頂堆:每一個節點的值都大於或等於其子節點的值,在堆排序算法中用於升序排列
  • 小頂堆:每一個節點的值都小於或等於其子節點的值,在堆排序算法中用於降序排列

代碼以下:

var len;    //由於聲明的多個函數都須要數據長度,因此把len設置成爲全局變量

function buildMaxHeap(arr) {   //創建大頂堆
    len = arr.length;
    for (var i = Math.floor(len/2); i >= 0; i--) {
        heapify(arr, i);
    }
}

function heapify(arr, i) {     //堆調整
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

function heapSort(arr) {
    buildMaxHeap(arr);

    for (var i = arr.length-1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}
複製代碼

堆排序動圖演示:

8、計數排序

算法介紹:

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

代碼以下:

function counting_sort(arr, maxValue) {
    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]--;
        }
    }

    return arr;
}
複製代碼

計數排序動圖演示:

9、桶排序

桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。 爲了使桶排序更加高效,咱們須要作到這兩點:

在額外空間充足的狀況下,儘可能增大桶的數量 使用的映射函數可以將輸入的N個數據均勻的分配到K個桶中 同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響相當重要。 何時最快(Best Cases):

  • 當輸入的數據能夠均勻的分配到每個桶中 何時最慢(Worst Cases):
  • 當輸入的數據被分配到了同一個桶中

代碼演示:

function bucketSort(arr, bucketSize) {
    if (arr.length === 0) {
      return arr;
    }

    var i;
    var minValue = arr[0];
    var maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {
      if (arr[i] < minValue) {
          minValue = arr[i];                //輸入數據的最小值
      } else if (arr[i] > maxValue) {
          maxValue = arr[i];                //輸入數據的最大值
      }
    }

    //桶的初始化
    var DEFAULT_BUCKET_SIZE = 5;            //設置桶的默認數量爲5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;   
    var buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) {
        buckets[i] = [];
    }

    //利用映射函數將數據分配到各個桶中
    for (i = 0; i < arr.length; i++) {
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }

    arr.length = 0;
    for (i = 0; i < buckets.length; i++) {
        insertionSort(buckets[i]);                      //對每一個桶進行排序,這裏使用了插入排序
        for (var j = 0; j < buckets[i].length; j++) {
            arr.push(buckets[i][j]);                      
        }
    }

    return arr;
}
複製代碼

10、基數排序

基數排序須知:

基數排序有兩種方法:

  • MSD 從高位開始進行排序
  • LSD 從低位開始進行排序

基數排序 vs 計數排序 vs 桶排序:

這三種排序算法都利用了桶的概念,但對桶的使用方法上有明顯差別:

  • 基數排序:根據鍵值的每位數字來分配桶
  • 計數排序:每一個桶只存儲單一鍵值
  • 桶排序:每一個桶存儲必定範圍的數值

代碼演示:

function radix_sort(arr, maxDigit) {
        var mod = 10;
        var dev = 1;
        var counter = [];
        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;
                    }
                }
            }
        }
        return arr;
    }
複製代碼

基數排序動圖演示:

歡迎關注

參考:www.cnblogs.com/liyongshuai…

相關文章
相關標籤/搜索