JavaScript之排序算法

1、冒泡排序

  原理:1.比較相鄰的元素。若是第一個比第二個大,就交換兩個數;2.對每一對相鄰元素重複作步驟一,從開始第一對到結尾的最後一對,該步驟結束會產生一個最大的數;3.針對全部的數重複以上的步驟(最後一個數除外);4.持續每次對愈來愈少的數重複上面步驟,直到沒有任何一對數須要比較。web

冒泡排序示意圖

 1 function bubbleSort(arr) {
 2             let len = arr.length
 3             // 外層循環爲執行次數
 4             for (let i = 0; i < len - 1; i++) {
 5                 // 外層循環爲相鄰兩個數的比較
 6                 for (let j = 0; j < len - i - 1; j++) {
 7                     if (arr[j] > arr[j + 1]) {
 8                         sort(arr, j, j + 1)
 9                     }
10                 }
11             }
12             return arr
13 
14         }
15 
16         function sort(arr, i, j) {
17             let temp = arr[i]
18             arr[i] = arr[j]
19             arr[j] = temp
20         }
21         let arr = [1, 5, -3, 8, 10]
22         console.log(bubbleSort(arr)) // [-3, 1, 5, 8, 10]

2、選擇排序。

  原理:1.首先在末拍序列中找到最小(大)值,存方法到排序序列的起始位置;2.再從剩餘末排序列中繼續尋找最小(大)值,而後放到已排序序列的末尾;3.重複步驟二,直到全部元素均排序完畢。算法

選擇排序示意圖

即:將數組中第一個數標記,而後依次和後面的數進行比較,若找到比標記的數大(小)時再將該數進行標記日後找,直到比較完後再進行位置交換shell

 1 function selectSort(arr){
 2             let len = arr.length,
 3                 minIndex,temp;
 4             for(let i = 0;i < len - 1;i++){
 5                 minIndex = i;
 6                 for(let j = i + 1;j < len;j++){
 7                     if(arr[j] < arr[minIndex]){
 8                         minIndex = j;
 9                     }
10                 }
11                 temp = arr[i];
12                 arr[i] = arr[minIndex];
13                 arr[minIndex] = temp;
14             }
15             return arr;
16         }
17         let arr = [3,8,9,4,3,0,7]   // [0, 3, 3, 4, 7, 8, 9]
18         console.log(selectSort(arr))

3、插入排序

  原理:1.將第一待排序列第一個元素看作一個有序序列,把第二個元素到最後一個函數當成是未排序序列;2.從頭至尾依次掃描未排序序列,將掃描到的每一個元素插入有序序列的適當位置(若是待插入的元素與有序序列中某個元素相等,則將待插入元素插入到相等元素的後面)。api

插入排序示意圖

  我的認爲該排序算法相對容易理解,哈哈!!!數組

 1  function insertSort(arr){
 2             let len = arr.length,
 3                 preIndex,current;
 4             for(let i = 1;i < len;i++){
 5                 preIndex = i -1;
 6                 current = arr[i];
 7                 while(preIndex >= 0 && arr[preIndex] > current){
 8                     arr[preIndex + 1] = arr[preIndex];
 9                     preIndex--
10                 }
11                 arr[preIndex + 1] = current;
12             }
13             return arr;
14         }
15         let arr = [-5,8,10,99,21,3];
16         console.log(insertSort(arr))    // [-5, 3, 8, 10, 21, 99]

4、希爾排序

  原理:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時,再對全體記錄進行依次直接插入排序數據結構

 1 function shellSort(arr){
 2     var gap = arr.length;
 3     while(gap>1){
 4         gap = parseInt(gap/2);
 5         for(var j=gap;j<arr.length;j++){
 6             var temp = arr[j];
 7             var i = j-gap;
 8             while(arr[i]>temp && i>=0){
 9                 arr[i+gap] = arr[i];
10                 i = i-gap;
11             }
12             arr[i+gap] = temp;
13         }
14     }
15      return arr;
16 }
17 let arr = [4, 2, 9, 1, 6, 8];
18         console.log(shellSort(arr))     // [1, 2, 4, 6, 8, 9]

例如:函數

 1 var arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,1];
 2 第一次,增量爲7,則分割爲:
 3 1-->[3, 26, 1]
 4 2-->[44, 27]
 5 3-->[38, 2]
 6 4-->[5, 46]
 7 5-->[47, 4]
 8 6-->[15, 19]
 9 7-->[36, 50]
10 進行排序後結果爲:
11 [1, 27, 2, 5, 4, 15, 36, 3, 44, 38, 46, 47, 19, 50, 26]
12 第二次,增量爲3,則分割爲:
13 1-->[1,5, 36, 38, 19]
14 2-->[27, 4, 3, 46, 50]
15 3-->[2, 15, 44, 47, 26]
16 進行排序後結果爲:
17 [1, 3, 2, 5, 4, 15, 19, 27, 26, 36, 46, 44, 38, 50, 47]
18 第三次,增量爲1,進行排序後爲:
19 [1, 2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50]

5、歸併排序

  原理:1.把長度爲n的輸入序列分紅兩個長度爲n/2的子序列;2.對這兩個子序列分別採用歸併排序;3.將兩個排序好的子序列合併成一個最終的排序序列。ui

歸併排序示意圖

 1     function mergeSort(arr){
 2             var len = arr.length;
 3             if(len < 2){
 4                 return arr;
 5             }
 6             var middle = Math.floor(len / 2),
 7                 left = arr.slice(0,middle),
 8                 right = arr.slice(middle);
 9             return merge(mergeSort(left),mergeSort(right));
10         }
11         function merge(left,right){
12             var result = [];
13             while(left.length && right.length){
14                 if(left[0] <= right[0]){
15                     result.push(left.shift());
16                 }else{
17                     result.push(right.shift());
18                 }
19             }
20             while(left.length)
21                 result.push(left.shift());
22 
23             while(right.length)
24                 result.push(right.shift());
25 
26             return result;
27         }
28         var arr = [2,5,1,6,-4,10]   
29         // let arr = [2,1]
30         console.log(mergeSort(arr))   // [-4,1,2,5,6,10]

6、快速排序

   原理:1.從數列中選出一個數以該數爲‘基準’;2.從新排序數列,全部元素比基準值小的排在前面,比基準值大的排在後面(和基準值相等的數可放在任何一邊)。在這個分區退出後,該基準就處於數列的中間位置,這個稱爲分區操做;3.遞歸地把小於基準值元素的子數列和大於基準值元素的子數列排序。spa

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

 1 function quickSort(arr){
 2             var len = arr.length
 3             if(len <= 2){
 4                 return arr;
 5             }
 6             var middle = parseInt(len / 2),
 7                 base = arr[middle],
 8                 left = [],
 9                 right = [];
10             for(var i = 0;i < len;i++){
11                 if(i === middle){
12                     continue;
13                 }
14                 if(arr[i] < base){
15                     left.push(arr[i]);
16                 }
17                 else{
18                     right.push(arr[i])
19                 }
20             }
21             return quickSort(left).concat(base,quickSort(right))
22         }
23     
24         var arr = [2, 9, 1, -5, -10, 6, 8, 7]
25         console.log(quickSort(arr))     // [-10, -5, 2, 1, 6, 7, 8, 9]

7、堆排序

   原理:1.將初始待排序關鍵字序列(R1,R2,...Rn)構建成大頂堆,此堆爲初始堆無無序區;2.將堆頂元素R[1]與最後一個元素R[n]交換,此時獲得新堆無序區(R1,R2,...,Rn-1)和新堆有序區(Rn),且知足R[1,2,...,n-1]<R[n];3.因爲交換後新堆堆頂R[1]可能違反堆的性質,所以須要堆當前無序區(R1,R2,...,Rn-1)調整爲新堆,而後再次將R[1]與無序區最後一個元素交換,獲得新的無序區(R1,R2,...,Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程,知道有序區的元素個數爲n-1,則整個排序過程完成。

  中心思想:利用這種數據結構設計的一種算法,即本身點的鍵值或索引老是小於(或大於)它的父節點。

 1     var len; // 由於聲明的多個函數都須要數據長度,因此把len設置成爲全局變量
 2 
 3         function buildMaxHeap(arr) { // 創建大頂堆
 4             len = arr.length;
 5             for (var i = Math.floor(len / 2); i >= 0; i--) {
 6                 heapify(arr, i);
 7             }
 8         }
 9 
10         function heapify(arr, i) { // 堆調整
11             var left = 2 * i + 1,
12                 right = 2 * i + 2,
13                 largest = i;
14 
15             if (left < len && arr[left] > arr[largest]) {
16                 largest = left;
17             }
18 
19             if (right < len && arr[right] > arr[largest]) {
20                 largest = right;
21             }
22 
23             if (largest != i) {
24                 swap(arr, i, largest);
25                 heapify(arr, largest);
26             }
27         }
28 
29         function swap(arr, i, j) {
30             var temp = arr[i];
31             arr[i] = arr[j];
32             arr[j] = temp;
33         }
34 
35         function heapSort(arr) {
36             buildMaxHeap(arr);
37 
38             for (var i = arr.length - 1; i > 0; i--) {
39                 swap(arr, 0, i);
40                 len--;
41                 heapify(arr, 0);
42             }
43             return arr;
44         }
45         var arr = [1, 2, 6, 8, 11, -7, 20]
46         console.log(heapSort(arr))      // [-7, 1, 2, 6, 8, 11, 20]

8、計數排序

   原理:1.找出待排序對數組中最大和最小對元素;2.統計數組中每一個值爲i的元素出現的次數,存入數組C的第i項;3.對全部的計數累加(從C中的第一個元素開始,每一項和前一項相加);4.反向填充目標數組,將每一個元素i放在心數組的第C(i)項,每放一個元素就將C(i)減去i;

  中心思想:使用額外的數組C,其中第i個元素時待排序數組A中值等於i的元素的個數,而後根據數組C來將A中的元素排到正確的位置,它只能對正整數進行排序。

 1  function countingSort(arr) {
 2             var len = arr.length;
 3             var min = max = arr[0],
 4                 result = [];
 5             for (var i = 1; i < len; i++) {
 6                 max = arr[i] > max ? arr[i] : max;
 7                 min = arr[i] < min ? arr[i] : min;
 8             }
 9             var newArr = new Array(max + 1);
10             newArr.fill(0);
11             for (var i = 0; i < len; i++) {
12                 newArr[arr[i]] = ++newArr[[arr[i]]];
13             }
14             for (var i = min - 1; i < max + 1; i++) {
15                 if (newArr[i] != 0) {
16                     while (newArr[i]) {
17                         result.push(i);
18                         --newArr[i];
19                     }
20                 }
21             }
22             return result;
23         }
24 
25         var arr = [2, 4, 6, 1, 7, 33, 50, 8]
26         console.log(countingSort(arr))      // [1, 2, 4, 6, 7, 8, 33, 50]

9、桶排序

   原理:1.設置一個定量的數組,當作 「空桶」;2.遍歷輸入數據,而且把數組一個一個放到對應的桶裏去;3.對每一個不是空桶進行排序;4.從不是空的桶裏把排好序的數據拼接起來。

  中心思想:計數排序的升級版。假設輸入數據服從均勻分佈,則數據分到有限數量到桶裏,沒每一個桶再分別排序(有可能再使用別的排序或是以遞歸方法繼續使用桶排序進行排序)

 1 function bucketSort(arr, num = 5) {
 2             var len = arr.length;
 3             if (len < 2 || singleArray(arr)) {
 4                 return arr;
 5             }
 6             var min = max = arr[0],
 7                 result = [];
 8             var temp = new Array(num);
 9             for (var i = 0; i < num; i++) {
10                 temp[i] = [];
11             }
12             for (var i = 0; i < len; i++) {
13                 max = arr[i] > max ? arr[i] : max;
14                 min = arr[i] < min ? arr[i] : min;
15             }
16             var gap = (max - min + 1) / num;
17             for (var i = 0; i < len; i++) {
18                 var index = parseInt((arr[i] - min) / gap);
19                 temp[index].push(arr[i]);
20             }
21             temp = temp.filter(function (item) {
22                 return item.length;
23             });
24             var tempLen = temp.length;
25             for (var i = 0; i < tempLen; i++) {
26                 temp[i] = bucketSort(temp[i]);
27                 result = result.concat(temp[i]);
28             }
29             return result;
30         }
31 
32         function singleArray(arr) { // 判斷數組各項是否相同
33             var len = arr.length;
34             for (var i = 1; i < len; i++) {
35                 if (arr[i] != arr[0]) {
36                     return false;
37                 }
38             }
39             return true;
40         }
41 
42         var arr = [1, 3, 8, -6, 11, 7, 99]
43         console.log(bucketSort(arr, 5))     // [-6, 1, 3, 7, 8, 11, 99]

例:

 1 var arr = [98,89, 89,1,2,3];
 2 (1)設置桶的數量爲5,找到最大值98,最小值1,每一個桶的範圍(98-1+1)/5=19.6
 3 (2)遍歷原始數據,以連標結構放到對應的桶中,數組98,索引值爲4(=parseInt(98-1)/19.6),數字89索引值爲4(=parseInt(89-1)/19.6),數字1,2,3的索引都爲0
 4 桶0–>[1,2,3]
 5 桶1–>[]
 6 桶2–>[]
 7 桶3–>[]
 8 桶4–>[98,89,89]
 9 (3)過濾掉爲空的桶
10 (4)遞歸地利用桶排序(或者其餘排序方法)對各個桶中的數組進行排序,若是數組長度爲1,或者數組中各項相同(相當重要),則直接返回數組
11 (5)將各桶合併

10、基數排序

   原理:1.取得數組中的最大值,並取得位數;2.arr爲原始數組,從最低位開始取每一個位組成radix數組;3.對radix進行計數排序(利用計數排序適用於小範圍的特色)

   中心思想:按照低位先排序,而後收集;再按照高位排序,而後再收集;依次類推,直到最高位。

  注:計數排序使用數據範圍較小(建議小於1000,且每一個數值都要大於0)

 1 function radixSort(arr) {
 2             var len = arr.length;
 3             var max = arr[0],
 4                 dev = 1,
 5                 mod = 10;
 6             for (var i = 1; i < len; i++) {
 7                 max = arr[i] > max ? arr[i] : max;
 8             }
 9             var radix = max.toString().length;
10             for (var j = 1; j <= radix; j++) {
11                 var result = [];
12                 var temp = new Array(10);
13                 for (var i = 0; i < 10; i++) {
14                     temp[i] = [];
15                 }
16                 for (var i = 0; i < len; i++) {
17                     var pos = parseInt(arr[i] % mod / dev);
18                     temp[pos].push(arr[i]);
19                 }
20                 dev *= 10;
21                 mod *= 10;
22                 for (var i = 0; i < 10; i++) {
23                     result = result.concat(temp[i]);
24                 }
25                 arr = result;
26             }
27             return arr;
28         }
29         var arr = [3,6,4,22,12,69]
30         console.log(radixSort(arr))     // [3, 4, 6, 12, 22, 69]

排序算法複雜度比較

n:數據規模

k:‘桶’的個數

In-place:佔用常數內存,不佔用額外內存

Out-place:佔用額外內存

穩定:假如 a 在 b 前面,而 a == b,排序以後 a 依然在 b 前面

不穩定:假如 a 在 b 前面,而 a == b,排序以後 a 可能就在 b後面

相關文章
相關標籤/搜索