做爲一個程序員,你怎麼能不瞭解冒泡算法呢?javascript
下面向你們介紹六中排序算法,並提供javascript實現,以及簡單分析算法複雜度。java
整體描述:
相鄰元素進行比較,每次選取最大的元素,進行下一次比較,所以能夠將最大的元素像冒泡同樣,從某一位置,到達最頂端
算法簡單描述:
假設:共有n個元素
進行(n-1)次循環,第i(從1開始計數)次循環得到第i大的元素,放在數組第(n-i)(數組從0開始計數)位
每次循環都從第一個元素開始,比較當前元素與其後一個元素的大小關係,若是後一個元素小於當前元素,則說明,當前元素較大,互換位置,即將(0~n-i區間最大的數放在n-i位),並將當前元素指向下一個位置,直到當前位置指向0,循環結束程序員
完整代碼:算法
function bubbleSort(originArr) { /* 數組副本 */ var cloneArr = originArr.concat(); /* 用於交換數據 */ var temp; /* 數組長度 */ var len = cloneArr.length; /* 每次選擇出最大的元素 */ /* 經過比較相鄰元素,將較大的元素放在後面,將較大的數繼續進行比較 */ for (var i = 0; i < len - 1; ++i) { // 須要執行len-1次 for (var j = 0; j < len - i; ++j) { // 須要執行len-i-1次 // 若是當前元素大於下一個元素,互換兩個元素 if (cloneArr[j] > cloneArr[j + 1]) { // 執行(1 + 2 + ... + n-1)算法複雜度爲O(n^2) temp = cloneArr[j]; cloneArr[j] = cloneArr[j + 1]; cloneArr[j + 1] = temp; } } } return cloneArr; }
整體描述:
每次選擇最小的元素,放在相應的位置上
算法簡單描述:
假設:共有n個元素
進行(n-1)次循環,第i(從1開始計數)次循環得到第i小的元素,放在數組第(i-1)(數組從0開始計數)位,第i次循環,從數組第(i-1)位開始,將該位置元素與其後全部元素進行比較,獲取較小元素索引,循環結束以後,將當前元素與最小索引位置元素位置互換,當前位置向前移動,進行下一輪循環,直到當前位置指向(n-1)shell
完整代碼:數組
function selectionSort(originArr) { /* 數組副本 */ var cloneArr = originArr.concat(); /* 用於交換數據 */ var temp; /* 存放最小元素索引 */ var minIndex = 0; /* 數組長度 */ var len = cloneArr.length; /* 從第一個位置開始,比較當前位置和後面全部元素,獲取最小元素後面的位置 */ for (var i = 0; i < len - 1; ++i) { // 須要執行len-1次 minIndex = i; // 獲取最小元素位置 for (var j = i + 1; j < len; ++j) { // 須要執行len-i-1次 if (cloneArr[minIndex] > cloneArr[j]) { // 執行(1 + 2 + ... + n-1)算法複雜度爲O(n^2) minIndex = j; } } // 若是最小元素所在索引,不是當前位置,交換元素 if (minIndex !== i) { temp = cloneArr[i]; cloneArr[i] = cloneArr[minIndex]; cloneArr[minIndex] = temp; } } return cloneArr; }
整體描述:
將數組分爲先後兩部分,前一部分是已排序的元素集合,後一部分是未排序的元素集合。每次選中未排序的第一個數組,插入到已排序集合中的合適的位置
算法簡單描述:
假設:共有n個元素
從第2個元素開始,進行(n-1)次循環,第i次循環,將第i個元素插入到以前位置(1~i-1)中,將當前元素依次後面元素進行比較。比較元素起始值爲當前元素前一位置元素,若是當前元素小於比較元素,比較元素向數組後面移動,當前元素繼續與下一個元素進行比較,直到比較元素位置爲0或者當前元素大於比較元素,將元素插入當前比較位置less
完整代碼:測試
function insertSort(originArr) { /* 數組副本 */ var cloneArr = originArr.concat(); /* 用於交換數據 */ var temp; /* 數組長度 */ var len = cloneArr.length; /* 循環數組中的每個元素 */ for (var i = 1; i < len; ++i) { // 須要執行len-1次 // 記錄要插入的值 temp = cloneArr[i]; // 找到合適的位置插入 for (var j = i - 1; j >= 0; --j) { // 須要執行i次 if (temp < cloneArr[j]) { // 執行(1 + 2 + ... + n-1)算法複雜度爲O(n^2) // 右移已排序數組 cloneArr[j + 1] = cloneArr[j]; } else { break; } } cloneArr[j + 1] = temp; } return cloneArr; }
整體描述:優化
希爾排序就是插入排序的優化,插入排序,每次將當前元素與以前的每個元素進行比較,而後插入,希爾排序,至關於先按照必定步長,將數組進行分組,對每一組進行插入排序,這樣就能夠大幅度的調整數據的分佈狀況,最後執行一次快速排序進行微調
算法簡單描述:
對於間隔數組中的每一個元素gap,將數組元素根據gap分爲gap組,對於每組進行插入排序ui
完整代碼:
function shellSort(originArr) { /* 數組副本 */ var cloneArr = originArr.concat(); /* 用於交換數據 */ var temp; /* 數組長度 */ var len = cloneArr.length; /* 間隔數組 */ var gap = []; /* 動態建立間隔數組 */ for (var i = Math.floor(len / 2); i > 0;) { gap.push(i); i = Math.floor(i / 2); } /* 使用間隔數組中的每個元素,選擇數組中的元素,進行快速排序 */ /* 方法1: 對每個間隔的每個分組進行快速排序 */ /*for (var i = 0, gapLen = gap.length; i < gapLen; ++i) { // 分爲gap[i]組分別進行排序 for (var j = 0; j < gap[i]; ++j) { // 第j組進行排序 for (var k = j + gap[i]; k < len; k = k + gap[i]) { temp = cloneArr[k]; while (k - gap[i] >= 0 && cloneArr[k - gap[i]] > temp) { cloneArr[k] = cloneArr[k - gap[i]]; k = k - gap[i]; } cloneArr[k] = temp; } } }*/ /* 方法2: 對於每個間隔,從間隔位置開始,對其後每個元素進行快速排序,保證前面的已經排好序 */ for (var i = 0, gapLen = gap.length; i < gapLen; ++i) { for (var j = gap[i]; j < len; ++j) { temp = cloneArr[j]; var k = j; while (k - gap[i] >= 0 && cloneArr[k - gap[i]] > temp) { cloneArr[k] = cloneArr[k - gap[i]]; k -= gap[i]; } cloneArr[k] = temp; }
// 最壞狀況O(n(logn)^2) 平均狀況O(n(logn)^2) } return cloneArr; }
整體描述:
每次選取一個基準值,將數組中其餘的元素和它進行比較,大於則移到數組右邊,小於則移到左邊。而後分類出來的數組繼續進行上述操做。
算法簡單描述:
選擇數組第一位元素位基準值,建立兩個新數組,分別存放小於基準值和大於基準值的元素。而後這兩個新數組遞歸進行上述操做,直到數組爲空。而後將左右數組和基準值進行拼接
完整代碼:
function quickSort(originArr) { /* 若是數組爲空,直接返回 */ if (originArr.length === 0) { return []; } /* 基準值 */ var pivot = originArr[0]; /* 分別存放大於小於數組 */ var lesser = []; var greater = []; /* 小於基準值,存放到lesser數組中,不然存放到greater數組中 */ for (var i = 1; i < originArr.length; ++i) { if (originArr[i] < pivot) { lesser.push(originArr[i]); } else { greater.push(originArr[i]); }
// 最壞狀況O(n^2) 平均狀況O(nlogn) } /* 將數組拼接後返回 */ return quickSort(lesser).concat(pivot, quickSort(greater)); }
整體描述:
自頂向下:先經過遞歸分解數組,再合併數組
算法簡單描述:
分解數組:若是數組長度不爲1,從中間將數組分爲兩部分,繼續分解
合併數組:將分解的數組融合,建立一個新數組,用於存放融合的數組元素。建立指針分別指向兩個數組的首位,比較當前指針指向位置元素的大小,將較小的元素插入新數組中,指針向後移動,直到有一個數組元素所有移出。最後檢查兩個數組,將未移出的元素追加到新數組中,最後存放已排序的數組根據對應位置存入待排序數組中
完整代碼:
function mergeSort(originArr) { /* 數組副本 */ var cloneArr = originArr.concat(); /* 調用歸併排序 */ doMergeSort(cloneArr, 0, cloneArr.length - 1); return cloneArr; } /* 向下分解數組,遞歸調用 */ function doMergeSort(arr, low, high) { if (low < high) { var mid = low + Math.floor((high - low) / 2); doMergeSort(arr, low, mid); doMergeSort(arr, mid + 1, high); merge(arr, low, mid, high);
// 最壞狀況O(nlogn) 平均狀況O(nlogn) } } /* 數組融合 */ function merge(arr, low, mid, high) { var p_low = low; var p_high = mid + 1; var sortArr = []; /* 比較左右部分元素,將較小的元素存放在sortArr前面 */ while (p_low <= mid && p_high <= high) { if (arr[p_low] > arr[p_high]) { sortArr.push(arr[p_high++]); } else { sortArr.push(arr[p_low++]); } } /* 將兩部分可能剩餘的元素複製到數組中 */ while (p_high <= high) { sortArr.push(arr[p_high++]); } while (p_low <= mid) { sortArr.push(arr[p_low++]); } /* 將已排序的數組複製到原數組對應位置 */ for (var i = low; i < high + 1; i++) { arr[i] = sortArr[i - low]; } }
100000數組測試: