前端(七)算法篇

算法篇

一、快速排序(Quick Sort)

快速排序的名字起的是簡單粗暴,由於一聽到這個名字你就知道它存在的意義,就是快,並且效率高! 它是處理大數據最快的排序算法之一了。算法

(1)算法簡介shell

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

(2)算法描述和實現數組

快速排序使用分治法來把一個串(list)分爲兩個子串(sub-lists)。具體算法描述以下:bash

  • <1>.從數列中挑出一個元素,稱爲 "基準"(pivot);
  • <2>.從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區退出以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做;
  • <3>.遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

Javascript代碼實現:數據結構

/*方法說明:快速排序
@param  array 待排序數組*/

var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];

var quickSort=function(arr){
    if(arr.length <= 1){
        return arr;
    }
    var keyIndex=Math.floor(arr.length / 2);
    var key=arr.splice(keyIndex,1)[0];
    var left=[];
    var right=[];
    for(var i=0;i<arr.length;i++){
        if(arr[i] < index){
            left.push(arr[i]);
        }else {
            right.push(arr[i]);
        }
    }
    
    return quickSort(left).concat([index],quickSort(right);
}
複製代碼

快速排序動圖演示:大數據

(3)算法分析ui

  • 最佳狀況:T(n) = O(nlogn)
  • 最差狀況:T(n) = O(n2)
  • 平均狀況:T(n) = O(nlogn)

二、冒泡排序(Bubble Sort)

(1)算法描述spa

冒泡排序是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是它們的順序錯誤就把它們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。這個算法的名字由來是由於越小的元素會經由交換慢慢「浮」到數列的頂端。prototype

(2)算法描述和實現

具體算法描述以下:

  • <1>.比較相鄰的元素。若是第一個比第二個大,就交換它們兩個;

  • <2>.對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數;

  • <3>.針對全部的元素重複以上的步驟,除了最後一個;

  • <4>.重複步驟1~3,直到排序完成。

JavaScript代碼實現:

傳統冒泡排序中每一趟排序操做只能找到一個最大值或最小值,咱們考慮利用在每趟排序中進行正向和反向兩遍冒泡的 方法一次能夠獲得兩個最終值(最大者和最小者) ,從而使排序趟數幾乎減小了一半。

function bubbleSort3(arr3) {
    var low = 0;
    var high= arr.length-1; //設置變量的初始值
    var tmp,j;
    while (low < high) {
        for (j= low; j< high; ++j) //正向冒泡,找到最大者
            if (arr[j]> arr[j+1]) {
                tmp = arr[j]; 
                arr[j]=arr[j+1];
                arr[j+1]=tmp;
            }
        --high;                 //修改high值, 前移一位
        for (j=high; j>low; --j) //反向冒泡,找到最小者
            if (arr[j]
複製代碼

冒泡排序動圖演示:

(3)算法分析

  • 最佳狀況:T(n) = O(n)

當輸入的數據已是正序時(都已是正序了,爲毛何須還排序呢....)

  • 最差狀況:T(n) = O(n2)

當輸入的數據是反序時(臥槽,我直接反序不就完了....)

  • 平均狀況:T(n) = O(n2)

三、選擇排序(Selection Sort)

表現最穩定的排序算法之一,由於不管什麼數據進去都是O(n²)的時間複雜度.....因此用到它的時候,數據規模越小越好。惟一的好處可能就是不佔用額外的內存空間了吧。

(1)算法簡介

選擇排序(Selection-sort)是一種簡單直觀的排序算法。它的工做原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。

(2)算法描述和實現

n個記錄的直接選擇排序可通過n-1趟直接選擇排序獲得有序結果。具體算法描述以下:

  • <1>.初始狀態:無序區爲R[1..n],有序區爲空;

  • <2>.第i趟排序(i=1,2,3...n-1)開始時,當前有序區和無序區分別爲R[1..i-1]和R(i..n)。該趟排序從當前無序區中-選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1..i]和R[i+1..n)分別變爲記錄個數增長1個的新有序區和記錄個數減小1個的新無序區;

  • <3>.n-1趟結束,數組有序化了。

Javascript代碼實現:

function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    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;                 //將最小數的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    console.timeEnd('選擇排序耗時');
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
複製代碼

選擇排序動圖演示:

(3)算法分析

  • 最佳狀況:T(n) = O(n2)
  • 最差狀況:T(n) = O(n2)
  • 平均狀況:T(n) = O(n2)

四、插入排序(Insertion Sort)

(1)算法簡介

插入排序(Insertion-Sort)的算法描述是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,一般採用in-place排序(即只需用到O(1)的額外空間的排序),於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。

(2)算法描述和實現

通常來講,插入排序都採用in-place在數組上實現。具體算法描述以下:

  • <1>.從第一個元素開始,該元素能夠認爲已經被排序;

  • <2>.取出下一個元素,在已經排序的元素序列中從後向前掃描;

  • <3>.若是該元素(已排序)大於新元素,將該元素移到下一位置;

  • <4>.重複步驟3,直到找到已排序的元素小於或者等於新元素的位置;

  • <5>.將新元素插入到該位置後;

  • <6>.重複步驟2~5。

Javascript代碼實現:

function insertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        console.time('插入排序耗時:');
        for (var i = 1; i < array.length; i++) {
            var key = array[i];
            var j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
        console.timeEnd('插入排序耗時:');
        return array;
    } else {
        return 'array is not an Array!';
    }
}
複製代碼

插入排序動圖演示:

(3)算法分析

  • 最佳狀況:輸入數組按升序排列。T(n) = O(n)
  • 最壞狀況:輸入數組按降序排列。T(n) = O(n2)
  • 平均狀況:T(n) = O(n2)

五、希爾排序(Shell Sort)

(1)算法描述和實現

先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,具體算法描述:

  • <1>. 選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;

  • <2>.按增量序列個數k,對序列進行k 趟排序;

  • <3>.每趟排序,根據對應的增量ti,將待排序列分割成若干長度爲m的子序列,分別對各子表進行直接插入排序。僅增量因子爲1 時,整個序列做爲一個表來處理,表長度即爲整個序列的長度。

Javascript代碼實現:

function shellSort(arr) {
    var len = arr.length,
        temp,
        gap = 1;
    console.time('希爾排序耗時:');
    while(gap < len/5) {          //動態定義間隔序列
        gap =gap*5+1;
    }
    for (gap; gap > 0; gap = Math.floor(gap/5)) {
        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;
        }
    }
    console.timeEnd('希爾排序耗時:');
    return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
複製代碼

(2)、希爾排序動態演示 假設咱們有以下7個元素,分別爲84, 25, 59, 71, 62, 16, 34,如今進行希爾排序。

第一輪選取全部元素數量的一半做爲增量,即7/2,取3,因此第一輪增量爲3,那麼第一組分組就是索引爲0,3,6對應的元素,即84,71,34,對其進行插入排序操做,

84當作已排序序列,接着準備將組內第二個元素71插入到已排序序列中,

71小於84,因此84後移到71原來的位置,

接着將組內第三個元素34插入到已排序序列中,首先與84比較,

34小於84,因此84後移,而後繼續與71比較,

34小於71,因此71後移,34放進去。而後開始處理第二組分組,第二組分組就是索引爲1,4對應的元素,即25,62,對其進行插入排序操做,

25當作已排序序列,接着將組內第二個元素62插入到已排序序列中,

25小於62,因此不移動。而後開始處理第三組分組,第三組分組就是索引爲2,5對應的元素,即59,16,對其進行插入排序操做,

59當作已排序序列,接着將組內第二個元素16插入到已排序序列中,

16小於59,因此59後移而16前移。至此處理完增量爲3的狀況。

第二輪增量爲上一輪增量的二分之一,即3/2,取1,因此第二輪增量爲1,此時全部元素組成同一個分組,對該組進行插入排序操做,首先將34當成已排序序列,準備將25插入到已排序序列,

25小於34,因而34後移,

繼續將下一個元素插入已排序序列中,1634比較,

16小於34,因而34右移,接着1625比較,

16小於25,25後移,16放進對應位置,

繼續將下一個元素插入已排序序列中,71與34比較,

34小於71,不移動,71放回原來位置,

繼續將下一個元素插入已排序序列中,62與71比較,

62小於71,因而71後移,接着62與34比較,

34小於62,不移動,62放到對應位置,

繼續將下一個元素插入已排序序列中,59與71比較,

59小於71,因而71後移,而後繼續與62比較,

59小於62,因而62也後移,而後繼續與34比較,

34小於59,因而34不移動,59放到對應位置,

繼續將下一個元素插入已排序序列中,已是最後一個元素了,84與71比較,

71小於84,因此不移動,此時已完成全部元素的希爾排序操做。

(3)算法分析

  • 最佳狀況:T(n) = O(nlog2 n)
  • 最壞狀況:T(n) = O(nlog2 n)
  • 平均狀況:T(n) =O(nlog n)

六、堆排序(Heap Sort)

(1)算法簡介

堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子結點的鍵值或索引老是小於(或者大於)它的父節點。

(2)算法描述和實現

具體算法描述以下:

  • 首先遍歷數組,判斷該節點的父節點是否比他小,若是小就交換位置並繼續判斷,直到他的父節點比他大 從新以上操做 1,直到數組首位是最大值

  • 而後將首位和末尾交換位置並將數組長度減一,表示數組末尾已經是最大值,不須要再比較大小

  • 對比左右節點哪一個大,而後記住大的節點的索引而且和父節點對比大小,若是子節點大就交換位置

  • 重複以上操做 3 - 4 直到整個數組都是大根堆。

Javascript代碼實現:

function heap(array) {
  checkArray(array);
  // 將最大值交換到首位
  for (let i = 0; i < array.length; i++) {
    heapInsert(array, i);
  }
  let size = array.length;
  // 交換首位和末尾
  swap(array, 0, --size);
  while (size > 0) {
    heapify(array, 0, size);
    swap(array, 0, --size);
  }
  return array;
}

function heapInsert(array, index) {
  // 若是當前節點比父節點大,就交換
  while (array[index] > array[parseInt((index - 1) / 2)]) {
    swap(array, index, parseInt((index - 1) / 2));
    // 將索引變成父節點
    index = parseInt((index - 1) / 2);
  }
}
function heapify(array, index, size) {
  let left = index * 2 + 1;
  while (left < size) {
    // 判斷左右節點大小
    let largest =
      left + 1 < size && array[left] < array[left + 1] ? left + 1 : left;
    // 判斷子節點和父節點大小
    largest = array[index] < array[largest] ? largest : index;
    if (largest === index) break;
    swap(array, index, largest);
    index = largest;
    left = index * 2 + 1;
  }
}

複製代碼

堆排序動圖演示:

(3)算法分析

  • 最佳狀況:T(n) = O(nlogn)
  • 最差狀況:T(n) = O(nlogn)
  • 平均狀況:T(n) = O(nlogn)

參考文章:十大經典排序算法總結(JavaScript描述)

相關文章
相關標籤/搜索