以前用 JavaScript 寫過 快速排序 和 歸併排序,本文聊聊四個基礎排序算法。(本文默認排序結果都是從小到大)javascript
冒泡排序每次循環結束會將最大的元素 "冒泡" 到最後一位。html
以 [1, 5, 2, 4, 3] 爲例,O(n^2) 的複雜度,總共外層循環 5 次,第一次循環結束後的結果是 [1, 2, 4, 3, 5]。 首先是 1 和 5 比較,1 <=5,不交換位置,而後 5 和 2 比較,5 > 2,交換位置,數組變爲 [1, 2, 5, 4, 3],而後 5 和 4 比較,交換位置,數組變爲 [1, 2, 4, 5, 3],最後 5 和 3 比較,交換位置,數組爲 [1, 2, 4, 3, 5],這個時候最大的元素 5 已經到了最後,整個交換過程當中大的元素就好像 "冒泡" 同樣冒出來。而後 [1, 2, 4, 3] 再進行一樣操做,以此類推。java
冒泡排序看起來不管最好狀況仍是最壞狀況,複雜度同樣,都是 O(n^2)。算法
function swap(array, a, b) { var tmp = array[a]; array[a] = array[b]; array[b] = tmp; } function bubbleSort(array) { var _array = array.concat(); for (var i = 0, len = _array.length; i < len; i++) for (var j = 0; j < len - 1 - i; j++) if (_array[j] > _array[j + 1]) swap(_array, j, j + 1); return _array; } var a = [1, 5, 2, 4, 3]; var ans = bubbleSort(a); console.log(ans); // [1, 2, 3, 4, 5]
選擇排序每次循環會找到最值元素的下標,而後將該元素交換到最前面。因此選擇元素每次循環交換一次,不會像冒泡同樣屢次交換。shell
仍是以 [1, 5, 2, 4, 3] 爲例,第一次循環比較,默認最值下標爲 0,最值爲 1,接着分別和 5,2,4,3 比較,ok 比完,最值的下標仍是 0,那麼就不交換(也能夠看作 array[0] 和 array[0] 交換)。接着進行第二輪,是爲 [5, 2, 4, 3] 進行循環,以此類推。數組
和冒泡相比,選擇排序也是不管好壞狀況,複雜度都是 O(n^2),而效率應該比冒泡稍微好點,畢竟交換次數少了。code
function swap(array, a, b) { var tmp = array[a]; array[a] = array[b]; array[b] = tmp; } function selectionSort(array) { var _array = array.concat(); for (var i = 0, len = _array.length; i < len; i++) { // 最值元素下標 var index = i; for (var j = i + 1; j < len; j++) if (_array[j] < _array[index]) index = j; swap(_array, i, index); } return _array; } var a = [1, 5, 2, 4, 3]; var ans = selectionSort(a); console.log(ans); // [1, 2, 3, 4, 5]
插入排序會比前面兩種排序算法高效。它將數組分紅 "已排序" 和 "未排序" 兩部分,一開始的時候,"已排序" 的部分只有一個元素,而後將它後面一個元素從 "未排序" 部分插入 "已排序" 部分,從而 "已排序" 部分增長一個元素,"未排序" 部分減小一個元素。以此類推,完成所有排序。(摘自阮老師的博文 http://javascript.ruanyifeng.com/library/sorting.html)htm
仍是以 [1, 5, 2, 4, 3] 爲例,外層仍是須要循環 5 次,假設循環到第三次,到 2 這個元素,前面已經有序,是爲 [1, 5],咱們要將 2 插入,首先比較 5 和 2,交換,此時數組前三項爲 [1, 2, 5],再比較 1 和 2,ok,不用交換了,有序了,比較結束。再看 4,第一次比較後,交換,數組爲 [1, 2, 4, 5],而後 4 和 2 比較,ok,有序了,不用繼續比了,那麼 2 就不用和 1 比較了,這樣就大大節省了相鄰元素兩兩比較的次數。blog
和前二者相比,插入排序能減小比較次數,固然最壞狀況下仍是 O(n^2),可是和選擇排序相比,可能會多交換次數。排序
function insertionSort(array) { var _array = array.concat(); for (var i = 0, len = _array.length; i < len; i++) { // 儲存當前位置的值 var item = _array[i]; // 和前面已經有序的部分,比較,交換 for (j = i - 1; j > -1 && _array[j] > item; j--) _array[j + 1] = _array[j]; _array[j+1] = item; } return _array; } var a = [1, 5, 2, 4, 3]; var ans = insertionSort(a); console.log(ans); // [1, 2, 3, 4, 5]
固然,真實生產環境中不可能用這三種排序方法,畢竟效率過低!不過必定要比較效率的話,我以爲是 插入排序 > 選擇排序 > 冒泡排序!
希爾排序是選擇排序的升級版,能夠說是分組插入排序,聽說複雜度達到 O(n^1.2)。
希爾排序是基於插入排序的如下兩點性質而提出改進方法的:
它是怎麼排序的呢?咱們設定一個變量叫作 gap,gap 小於數組長度,對於數組,咱們將距離 gap 的元素劃分爲一組,每組進行插入排序,gap 不斷變小,最後減爲 1,即完成希爾排序。
gap 如何取值?有個簡單一點的方法,第一次取值數組長度一半,而後再一半,再一半,最後爲 1。固然若是要求更高效率,能夠深刻研究下 gap 的取值。至於希爾排序爲何效率會比普通的插入排序高,這點不在本文探討範圍以內(實際上是我不知道),有興趣的能夠查閱相關資料。
// 希爾排序:先將整個待排序記錄序列分割成若干個子序列 // 在序列內分別進行直接插入排序,待整個序列基本有序時, // 再對全體記錄進行一次直接插入排序 function shellSort(array){ var len = array.length , gap = ~~(len >> 1); // 克隆數組 var result = array.concat(); while (gap > 0) { for(var i = gap; i < len; i++) { var tmp = result[i]; var j = i - gap; while (j >= 0 && tmp < result[j]) { result[j + gap] = result[j]; j -= gap; 1 } result[j + gap] = tmp; } gap = ~~(gap >> 1); } return result; } var a = [1, 5, 2, 4, 3]; var ans = shellSort(a); console.log(ans); // [1, 2, 3, 4, 5]
Read More: