排序方法 你真的懂嗎
阿新 • • 發佈:2018-12-08
一、選擇排序
選擇排序的思路:比如一個數組arr=[9,6,2,5,10,20,1]進行從小到大排序,我們讓每一個數字都和後面的數字進行比較,比自己小的就交換位置,比自己大的就進行下一個比較,將這個數放到相應的位置,下面是程式碼的實現:
function selectSort(arr){ var temp; //定義一個變數用來運算元字交換 for(var i=0;i<arr.length-1;i++){ for(var j=i+1;j<arr.length;j++){ if(arr[i]>arr[j]){ //簡單的交換位置邏輯,相信你可以看的懂 temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } return arr; }
二、快速排序
快速排序的思路:從一個數組中任意的挑選一個元素(通常來說我們會選擇中間的那個元素),將這個元素作為中軸元素,然後把剩下的元素以這個中軸元素的大小作為標準,比中軸元素小的放到左邊,比中軸元素大的放到右邊,然後把左邊和右邊的都作為一個數組,重複以上操作,知道子元素的元素個數小於等於1的時候,就證明全部的元素都已經從小到大排好序了(因為只有一個元素的陣列一定是有序的,已經不需要再繼續排序了),在這個演算法中我們主要是用到了了一個遞迴演算法(遞迴演算法不瞭解的建議可以先去看下這方面的知識),以下是程式碼的實現:
function quickSort(arr){ if(arr.length<=1){ return arr; } //獲取下標 var midIndex = arr.length%2 == 0?arr.length/2:(arr.length+1)/2; //取中間值 var mid = arr[midIndex]; //定義左邊的陣列 var left = []; //定義右邊的陣列 var right = []; for(var i=0;i<arr.length;i++){ if(i != midIndex && arr[i]<=mid){ left.push(arr[i]); } if(i != midIndex && arr[i]>mid){ right.push(arr[i]); } } return quickSort(left).concat(mid).concat(quickSort(right)) }
三、氣泡排序
氣泡排序的思路:顧名思義,氣泡排序,就像冒泡一樣,從小往大冒,由於邏輯過於簡單,在這裡我就直接貼出程式碼了:
function bubbleSort(arr){ var temp; for(var i=0;i<arr.length;i++){ for(var j=0;j<arr.length-i;j++){ if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } return arr; }
通過上面的程式碼可以看出來,通過兩次簡單的for迴圈,並且不加任何判斷語句的形式的演算法註定是低效的,以下是對氣泡排序演算法的三種優化
(1)、當我們對一個數組arr=[9,1,2,3,4,5,6]進行排序的時候,我們正常氣泡排序的話,還是會每個數字都排一次,但事實上我們第一次排序進行完之後,陣列就已經變成[1,2,3,4,5,6,9],已經達到我們想要的效果了,所以已經不需要再進行其他元素的排序了,所以我們要對這種傳統的氣泡排序演算法做一個優化,思路大概是這樣的:我們定義一個flag,當某一次排序中沒有發生元素的交換的話,設定flag為false,當flag為false的時候直接結束後面的迴圈,這樣的話陣列就不會再進行後面的無意義的排序了,程式碼實現:
var arr = [9,1,2,3,4,5,6] function bubbleSort(arr){ var temp; var flag; //定義flag,用來判斷陣列是否已經有序 for(var i=0;i<arr.length;i++){ flag = true //我們設定flag初始值為true for(var j=0;j<arr.length-i;j++){ if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = false; //我們自己規定flag為false的時候說明陣列需要繼續排序 } } if(flag){ //我們可以規定如果某次迴圈後flag依然為true的話,表明這次沒有進行重新的元素交換,也就是說沒有進行重新排序,那麼此時陣列中元素已經有序了,所以我們可以直接break跳出迴圈,return出陣列 break; } } return arr; }
(2)、第二種優化是從另一個角度來考慮的,並且也是基於第一次優化的思想,我們每次排序後,陣列的後面有一部分已經有序了,所以我們也不需要再和後面已經排好序的元素再進行比較了,我們可以這樣做,用一個變數來記錄下最後一次發生交換的位置,後面沒有發生交換的其實已經有序了,所以可以用這個值來作為一一次我們比較結束時的位置,將會減少很多次沒必要的排序過程,程式碼實現如下:
var arr = [9,1,10,5,6,3,0] function bubbleSort(arr){ var temp; var flag; //定義flag,用來判斷陣列是否已經有序 var lastindex = 0; //定義lastindex,用來判記錄每次排好序時的最後一次交換的位置 var k = arr.length-1; //用來和lastindex配合,作為每次迴圈的邊界值,實現不會進行沒必要排序的效果 for(var i=0;i<arr.length;i++){ flag = true //我們設定flag初始值為true for(var j=0;j<k;j++){ if(arr[j]>arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = false; //我們自己規定flag為false的時候說明陣列需要繼續排序 lastindex = j; //來記錄最後一次交換元素的下標 } } k = lastindex if(flag){ //我們可以規定如果某次迴圈後flag依然為true的話,表明這次沒有進行重新的元素交換,也就是說沒有進行重新排序,那麼此時陣列中元素已經有序了,所以我們可以直接break跳出迴圈,return出陣列 break; } } return arr; }
在這裡我只寫了兩種優化的方法,可我為什麼說有三種呢,是我覺得肯定還會有第三種第四種等等很多,等待著我們後續的思考,做了前端也快三年了,效能優化這塊兒在各個方面都有很多,還有原生js也不能丟,我就是說一說自己的一些想法:),希望同行們(為夢想奮鬥中的我們),在使用框架或者一些類庫來工作的同時,最底層最原理的東西也不能丟,我自己都不知道我現在在說什麼,就是感覺我們不能丟了最原始的東西,好了,今天就到這裡了,各位晚安,勿忘初心,方得始終~~~