一:冒泡排序算法
1. 原理shell
a. 從頭開始比較相鄰的兩個待排序元素,若是前面元素大於後面元素,就將二個元素位置互換編程
b. 這樣對序列的第0個元素到n-1個元素進行一次遍歷後,最大的一個元素就「沉」到序列的最後位置(第n-1個位置,n爲待排序元素個數)數組
c.排除這次排序最後面的那個元素(n=n-1),繼續對剩餘序列重複前面兩步瀏覽器
d. 當(n= n-1)=0時,排序完成app
2. 具體實現測試
以以下待排序序列爲例:ui
到此,第一次冒泡完成,最大值7冒泡到最後面。spa
而後繼續對除最後元素(7)外的序列進行冒泡排序。具體實現以下:3d
/** * 冒泡排序 * @param {Array} arr - 整型數組 * @returns {Array} ret - 排好序的數組 */ function bubbleSort(arr) { var n = arr.length, i = 0, temp; while(--n) { while (i < n) { // 若是前一個數大於後一個數,則互換位置 if(arr[i] > arr[i+1]) { temp = arr[i]; arr[i] = arr[i+1]; arr[i+1] = temp; } i++; } // 每次冒泡完成後,將i復位 i = 0; } return arr; } // 基於qunit的測試 test('bubble-sort', function () { var arr1 = [6,2,4,3]; var arr2 = [28,13,4,19,10]; var arr3 = [2,3,2,4,2,5]; propEqual(bubbleSort(arr1), [2,3,4,6]); propEqual(bubbleSort(arr2), [4,10,13,19,28]); propEqual(bubbleSort(arr3), [2,2,2,3,4,5]); });
二:選擇排序
1. 原理
a. 首先在待排序序列中找到最小元素,放入儲存有序序列中。同時從待排序序列中刪除這個元素
b. 繼續從未排序序列中找到最小元素,而後a步中的有序列序列中
c. 以此類推,直到待排序序列元素個數爲0
2. 具體實現:
/** * 選擇排序 * @param {Array} arr * @returns {Array} ret */ function selectionSort(arr) { var ret = [], min, i; while(arr.length) { // TODO 應該本身實現一個求數組中的最小值方法 min = Math.min.apply(null, arr); ret.push(min); // 從待排序數組中刪除這個元素 arr.splice(arr.indexOf(min), 1); } return ret; } // qunit test('selection-sort', function () { var arr1 = [1,5,3,6,4,2]; var arr2 = [1,5,4,6,4,2]; propEqual(selectionSort(arr1), [1,2,3,4,5,6]); propEqual(selectionSort(arr2), [1,2,4,4,5,6]); });
三: 插入排序
1. 排序原理:
a. 從待排序序列第0個元素開始排序,該元素能夠認爲已是有序的
b. 取出下一個元素,在已經排序的元素序列中從後向左遍歷
c. 若是已排序元素大於新元素,將該元素移到下一位置
d. 重複步驟c,直到找到一個已排序的元素,此元素不大於新元素;或者元素位於有有序序列開始位置
e. 將新元素插入到此元素後面
f. 重複步驟b~e,直接待排元素個數爲0
2. 具體實現
/** * 插入排序 * @param {Array} arr * @returns {Array} ret */ function insertionSort(arr) { // 從1開始,由於一個元素的序列,始終是有序的 for(var i = 1, j; i < arr.length; i++) { j = i; // 保存待排序元素 v= arr[j]; // 若是有序序列中的元素大於待插入的元素,則有序列序列中的元素向後移動一個位置 // 向後移到一個位置,會覆蓋待排序的元素,但咱們前面有保存待排序元素,因此待排序元素不會丟失 // 同時,也留出一個位置,以插入待排序元素 // 直到找一個已經排序的元素,其不大於待排序元素,將待排序元素插入到這裏。 // 若是遍歷到有序序列的開始位置,也不存在一個元素不大於待排序元素,則將待排序元素插入到已經排序序列的開始 while(arr[j-1] > v) { arr[j] = arr[j-1]; j--; if(j === 0) { break; } } arr[j] = v; } return arr; } // qunit test('insertion-sort', function () { var arr1 = [1,5,3,6,4,2]; var arr2 = [1,5,4,6,4,2]; propEqual(insertionSort(arr1), [1,2,3,4,5,6]); propEqual(insertionSort(arr2), [1,2,4,4,5,6]); });
四:希爾排序
1. 排序原理:
a. 設定一個間距d,將待排序序列分組
b. 對分組使用插入排序
c. 改變d, 再次分組
d. 再次對上面的分組使用插入排序
e. 重複上面的步驟,直至d爲1,並進行最後一次插入排序,獲得排好序的序列
2. 具體實現
希爾排序過程當中,涉及到選擇一組間距序列,這個序列叫叫希爾增量。希爾增量的奧妙之後有時間再研究。
/** * 希爾排序 * @param {Array} arr * @returns {Array} */ function shellSort(arr) { // 動態取得一個希爾增量 var N = arr.length; var h = 1; var i, j, v; // 產生希爾增量序列第一個值 while (h < N / 3) { h = 3 * h + 1; // ① } // 對分組使用插入排序,同時改變希爾增量值,直到其爲1,並進行最後一次插入排序,獲得有序序列 // 第一次插入排序,都是能夠將待排序序列排成有序序列的 // 不停運用插入排序,實際上是減小了元素在排序過程當中移動的次數 while (h >= 1) { for (i = 1; i < arr.length; i++) { j = i; v = arr[j]; while (j > 0 && arr[j - 1] > v) { arr[j] = arr[j - 1]; j--; } arr[j] = v; } h = (h - 1) / 3; // 從①能夠保證,確定能除盡的 } return arr; } // qunit test('shell-sort', function () { var arr1 = [1,5,3,6,4,2,22,34,11,12,45]; var arr2 = [1,5,4,6,4,2]; propEqual(shellSort(arr1), [1,2,3,4,5,6,11,12,22,34,45]); propEqual(shellSort(arr2), [1,2,4,4,5,6]); });
五. 歸併排序
1. 排序原理:
歸併排序主要分兩步:
a. 分組
對待排序序列按二分法分紅兩個小序列,並一直遞歸下去,直到序列長度爲1(長度爲1 的序列是有序的)
b. 合併
將排好序的數組合併成有序數列,最後獲得排序結果
2. 具體實現
// 歸併排序 function mergetSort(arr) { if(arr.length === 1) { return arr; } var leftArr = arr.slice(0, Math.floor(arr.length / 2)); var rightArr = arr.slice(leftArr.length); // 遞歸 return merge(mergetSort(leftArr), mergetSort(rightArr)); // 合併有序序列 function merge(arrLeft, arrRight) { var indexLeft = 0, indexRight = 0, sl = arrLeft.length, sr = arrRight.length, ret = []; while(true) { if(indexLeft < sl && indexRight < sr) { if(arrLeft[indexLeft] < arrRight[indexRight]) { ret.push(arrLeft[indexLeft]); indexLeft++; } else { ret.push(arrRight[indexRight]); indexRight++; } } else { if(indexLeft < indexRight) { ret = ret.concat(arrLeft.slice(indexLeft)); } else { ret = ret.concat(arrRight.slice(indexRight)); } break; } } return ret; } } // qunit test('merge-sort', function () { var arr1 = [28,13,4,19,10]; var arr2 = [1,5,4,6,4,2]; propEqual(mergetSort(arr1), [4,10,13,19,28]); propEqual(mergetSort(arr2), [1,2,4,4,5,6]); });
六: 快速排序
1. 排序原理
a. 從序列中挑出一個元素,稱爲 "基準"(pivot),
b. 從新排序序列,全部元素比基準值小的元素擺放在基準前面,全部元素比基準值大的擺在基準後面
c. 把新獲得的序列再經過上面的方法排序。當序列長度爲1或0時結束遞歸
2. 具體實現
// 快速排序 function quickSort(arr) { var pivot = arr[0]; var i = 1; var leftArr= [], rightArr = []; if(arr.length === 0) { return []; } if(arr.length === 1) { return arr; } for(; i < arr.length; i++) { if(arr[i] < pivot) { leftArr.push(arr[i]); } else { rightArr.push(arr[i]); } } return quickSort(leftArr).concat(pivot, quickSort(rightArr)); } // qunit test('quick-sort', function () { var arr1 = [6,2,4,3]; var arr2 = [28,13,4,19,10]; var arr3 = [4,1,7,3,5,2,6]; propEqual((quickSort(arr1)), [2,3,4,6]); propEqual(quickSort(arr2), [4,10,13,19,28]); propEqual(quickSort(arr3), [1,2,3,4,5,6,7]); });
小結:
本文把常見的排序算法(冒泡,選擇,插入,希爾,歸併,快速排序)基於JS實現了一遍,練習一下算法,仍是有助於提升編程思惟的。好比求一個數組的最大值。咱們知道能夠這樣:
var max = Math.min.applu(null, arr)
可是瀏覽器內部是怎麼實現的呢,又或者假設瀏覽器沒提供這個方法,咱們本身怎麼作呢?其實經過一次向左冒泡就能夠獲得最小值:
function getMinValue(arr) { var i = arr.length, j; j = i; while(--j) { if(arr[j - 1] > arr[j]) { arr[j - 1] = [arr[j - 1], arr[j]]; arr[j] = arr[j - 1][0]; arr[j- 1] = arr[j - 1][1]; } } // 返回最小值 return arr[0]; }