js算法之最經常使用的排序

js算法之最經常使用的排序

參加百度前端的課程真的是好多知識點不知道。邊學邊作題,在問題中學習,知識點從點到面,可是要善於總結記錄才行。加油吧,騷年!javascript

可視化排序網站

時間複雜度是衡量一個算法效率的基本方法
咱們把它記做:O(n)html


冒泡排序(Bubble sort)

大白話介紹:比較相鄰的兩個數,若是後面的比前面的小,把小的放在前面。
時間複雜度: O(n2)
動畫演示:冒泡算法
實際代碼:前端

(優化算法:若是數組已是有序了,就不必再比較了):
var arr=[5,3,2,4,1,0];
function bubbleSort(arr){
    var flag = false;  // 定義一個變量爲false,未交換位置
    for(var i=0;i<arr.length-1;i++){
        for(var j=0;j<arr.length-1;j++){
            if(arr[j+1]<arr[j]){
                temp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = temp;
                flag = true; //true,已交換位置
            }
        }
        if(flag){
            flag = false; //若是交換了位置,將flag從新設爲false
        }else{
             break;       //若是未交換,則跳出循環
        }
    }
    return arr;
}
document.write(bubbleSort(arr));  //0,1,2,3,4,5

優化方法設置一箇中斷標誌位,在條件測試中若是發生了交換就將中斷位屏蔽,而後在外層循環中檢查中斷位,若是中斷位沒有被屏蔽,將結束循環。每次開始內層循環以前重置中斷位。這樣就能夠在已是正序排列時不繼續進行循環,達到最優的複雜度.java

計算時間複雜度主要是看這幾個指標:
1 input size(輸入)linux

2 basic operation/most costly operation(基本操做)
3 determine average cases(決定最壞和平均的時間)
4 sove it(計算)
在冒泡排序中的核心部分是
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)
if(a[j+1]<a[j]) swap(a[j],a[j+1]);web

根據上面的步驟
1 size = n
2 basic operation = key comparison(比較)
由於比較是每次都要作的,而交換不必定每次都要作
3 average case = worst case
4 solve it
就是計算一共進行多少次比較這裏就是用數學裏的求和公式sigma求出來
最內層循環key comparison的次數是從0到n-i-1,外層循環i從0到n-1
因此總數是對(n-1-i)求和,i從0到n-1
(n-1)*n - (1+2+3+4+…+n-1)= n(n-1)/2 = O(n^2)
因此時間複雜度是n的平方算法


選擇排序

大白話介紹:先從原始數組中選擇一個最小的數據,和第一個位置1的數據交換。再從剩下的n-1個數據中選擇次小的數據,將其和第二個位置的數據交換。不斷重複,知道最後兩個數據完成交換。能夠很清楚的發現,選擇排序是固定位置,找元素.
時間複雜度:O(n2)
動畫演示:選擇排序
實際代碼:數組

var arr=[5,3,2,4,1,0];
function selectionSort(array){
    var min,temp;
    for(var i=0; i<array.length-1; i++){
        min=i; 
        for(var j=i+1; j<array.length; j++){
            if(array[j]<array[min]){
                min=j;
            }
        }
        swap(array,min,i);
            
    }
        return array;
}//選擇排序
function swap(array,i,j){
    var temp =array[i];
    array[i]=array[j];
    array[j]=temp;
}//兩個數字交換 

    document.write(selectionSort(arr));  //0,1,2,3,4,5

分析:
從選擇排序的思想或者是上面的代碼中,咱們都不難看出,尋找最小的元素須要一個循環的過程,而排序又是須要一個循環的過程。所以顯而易見,這個算法的時間複雜度也是O(n*n)的。這就意味值在n比較小的狀況下,算法能夠保證必定的速度,當n足夠大時,算法的效率會下降。而且隨着n的增大,算法的時間增加很快。所以使用時須要特別注意。性能


快速排序

也是在實際中最經常使用的一種排序算法,速度快,效率高。就像名字同樣,快速排序是最優秀的一種排序算法。
大白話:學習

(1)在數據集之中,選擇一個元素做爲"基準"(pivot)。

(2)全部小於"基準"的元素,都移到"基準"的左邊;全部大於"基準"的元素,都移到"基準"的右邊。
(3)對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到全部子集只剩下一個元素爲止。

代碼:

var arr=[77,-33,22,32,0,2,11];
    function quickSort(arr){
        if(arr.length<=1){ //若是數組中只有一位數,返回數組
            return arr;
        }
        var mNumIndex = Math.floor(arr.length/2); //取基準值的下標
        var mNum = arr.splice([mNumIndex],1)[0];  //取基準值
        var left = [];  //左邊數組
        var right = []; //右邊數組
        
        for(var i=0;i<arr.length;i++){
            if(arr[i]<mNum){  //若是數組小於基準值,放在左邊數組
                left.push(arr[i]);
            }else{            ///不然
                right.push(arr[i]);
            }
        }        
        return quickSort(left).concat([mNum],quickSort(right)); //返回左邊數組+基準值+右邊數組
    }

    document.write(quickSort(arr));//-33,0,2,11,22,32,77

分析

快速排序的時間主要耗費在劃分操做上,對長度爲k的區間進行劃分,共需k-1次關鍵字的比較。

最壞狀況是每次劃分選取的基準都是當前無序區中關鍵字最小(或最大)的記錄,劃分的結果是基準左邊的子區間爲空(或右邊的子區間爲空),而劃分所得的另外一個非空的子區間中記錄數目,僅僅比劃分前的無序區中記錄個數減小一個。時間複雜度爲O(n*n)

在最好狀況下,每次劃分所取的基準都是當前無序區的"中值"記錄,劃分的結果是基準的左、右兩個無序子區間的長度大體相等。總的關鍵字比較次數:O(nlgn)

儘管快速排序的最壞時間爲O(n2),但就平均性能而言,它是基於關鍵字比較的內部排序算法中速度最快者,快速排序亦所以而得名。它的平均時間複雜度爲O(nlgn)。


插入排序

大白話:首先對前兩個數據從小到大比較。接着將第三個數據與排好的前兩個數據比較,將第三個數據插入合適的位置。以此類推。(插入排序有兩個循環,外循環將數組挨個移動,內循環將對外循環選中的元素及他前面的數進行比較。)
時間複雜度:O(n^2)
代碼:

var arr=[5,3,2,4,1,0];
function insertSort(arr){
    var temp, j;
    for(var i=1; i<arr.length; i++){
        temp =arr[i];
        j=i;
        while(j>0 && arr[j-1]>temp){
            arr[j]=arr[j-1];
            j--;
        }
        arr[j]=temp;

    }
    return arr;
}
document.write(insertSort(arr));  //0,1,2,3,4,5

分析

(插入排序有兩個循環,外循環將數組挨個移動,內循環將對外循環選中的元素及他前面的數進行比較。)
插入排序的思路很簡單,很清晰,是一種最多見最簡單的排序方法,。可是能夠看出,因爲須要兩層循環,外層循環n-1次,內層循環每次遞增一次。當輸入徹底從小到大有序時,只須要常數的時間,這固然是最好的狀況。可是咱們不能指望輸入,當輸入徹底逆序時,最壞的狀況就出現了,顯然時間複雜度是O(n*n)的。咱們都很清楚,這個時間複雜度在排序中並不能算好的。這也是爲何插入排序雖然簡單,但並無被普遍應用的緣由所在。


歸併排序(mergeSort)

大白話介紹: 把一個數組分爲兩個數組,左邊排好序,右邊排好序,而後合併到一塊兒排序
專業性介紹: 歸併排序是分治法的典型實例,指的是將兩個已經排序的序列合併成一個序列的操做
時間複雜度: O(nlogn)
實際代碼:

var arr=[-11,17,12,19,0,-222];
     function mergeSort(arr,s,e){
         if(s>e){   //起始位置大於終點位置,返回空數組
             return [];
         }else if(s==e){
             return [arr[s]]; //起始位置等於終點位置,說明數組裏只有一個數字,返回只含一個數字的數組    
         }

         var mIndex = Math.floor((s+e)/2); //中間位置的Index
         var arrL = mergeSort(arr,s,mIndex); //將左邊的數組排序
         var arrR = mergeSort(arr,mIndex+1,e); //將右邊的數組排序
         
         var resultArr = []; //結果數組
         while(arrL.length>0 || arrR.length>0){ //當左右兩個數組都不爲空時
             if(arrL[0]<arrR[0]){
                 resultArr.push(arrL.shift());
             }else{
                 resultArr.push(arrR.shift());
             }

             if(arrL.length==0){  //當左邊的數組爲空時
                 resultArr = resultArr.concat(arrR);
                 break;
             }else if(arrR.length==0){
                 resultArr = resultArr.concat(arrL);
                 break;
             }
         }
         return resultArr;
     }

     document.write(mergeSort(arr,0,arr.length-1))

參考資料:
1.算法的時間複雜度
2.算法的時間複雜度分析
3.如何計算時間複雜度
4.js算法之最經常使用的排序
5.快速排序(Quicksort)的Javascript實現
6.排序算法——快速排序

相關文章
相關標籤/搜索