隨時隨地滿電出行,羅馬仕20000毫安超薄快充移動電源69元
一,氣泡排序
思路:
- 對未排序的各元素從頭到尾依次比較相鄰的兩個元素大小關係
- 如果左邊的隊員高, 則兩隊員交換位置
- 向右移動一個位置, 比較下面兩個隊員
- 當走到最右端時, 最高的隊員一定被放在了最右邊
- 按照這個思路, 從最左端重新開始, 這次走到倒數第二個位置的隊員即可.
- 依次類推, 就可以將資料排序完成
時間複雜度:
> 大 O 表示法
>
> - 比較次數:O(N^2)
> - 交換次數:O(N^2)
function bubbleSort(arr){ var length = arr.length; for (var i = arr.length;i > 0;i--){ for (var j = 0;j < i; j++){ if(arr[j] > arr[j+1]){ [arr[j],arr[j+1]]=[arr[j+1],arr[j]]; } } } return arr }
二,選擇排序
思路:
- 選定第一個索引位置,然後和後面元素依次比較
- 如果後面的隊員, 小於第一個索引位置的隊員, 則交換位置
- 經過一輪的比較後, 可以確定第一個位置是最小的
- 然後使用同樣的方法把剩下的元素逐個比較即可
- 可以看出選擇排序,第一輪會選出最小值,第二輪會選出第二小的值,直到最後
時間複雜度:
> 大 O 表示法
>
> - 比較次數:O(N^2)
> - 交換次數:O(N)
function selectionSort(arr) { var length = arr.length; for (let i = 0; i < length; i++) { var minIndex = i; for (let j = i + 1; j < length; j++) { if (arr[minIndex] > arr[j]) { minIndex = j; } } [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; } return arr; }
三,插入排序
思路:
- 從第一個元素開始,該元素可以認為已經被排序
- 取出下一個元素 temp,在已經排序的元素序列中從後向前掃描
- 如果該元素(已排序的元素)大於新元素 temp,將該元素移到下一位置
- 重複上一個步驟,直到找到已排序的元素小於或者等於新元素 temp 的位置
- 將新元素插入到該位置後, 重複上面的步驟
時間複雜度:
> 大 O 表示法
>
> - 比較次數:O(N^2)
> - 交換次數:O(N)
function insertionSort(arr) { for (var i = 1;i < arr.length;i++) { var tmp = arr[i]; for (var j = i - 1;j >= 0 && arr[j] > tmp;j--) { arr[j + 1] = arr[j]; } arr[j + 1] = tmp; } return arr; }
四,希爾排序
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個檔案恰被分成一組,演算法便終止。
選擇合適的增量:
- 在希爾排序的原稿中, 他建議的初始間距是 N / 2, 簡單的把每趟排序分成兩半.
- 也就是說, 對於 N = 100 的陣列, 增量間隔序列為: 50, 25, 12, 6, 3, 1.
- 這個方法的好處是不需要在開始排序前為找合適的增量而進行任何的計算.
- 我們先按照這個增量來實現我們的程式碼.
function shellSort(arr) { var length = arr.length; var gap = Math.floor(length / 2); //增量 while (gap > 0) { // 插入排序 for (let i = gap; i < length; i++) { // 儲存臨時變數 var j = i; var temp = arr[i]; while (j > gap - 1 && arr[j - gap] > temp) { arr[j] = arr[j - gap]; j -= gap; } arr[j] = temp; } gap = Math.floor(gap / 2); //更新增量 } return arr; }
五,快速排序
1. 在陣列中選一個基準數(通常為陣列第一個);
2. 將陣列中小於基準數的資料移到基準數左邊,大於基準數的移到右邊;
3. 對於基準數左、右兩邊的陣列,不斷重複以上兩個過程,直到每個子集只有一個元素,即為全部有序。
取基準值為陣列最左邊的數
function quickSort(arr, left = 0, right = arr.length - 1) { if (left >= right) return; var baseId = left, baseVal = arr[baseId], i = left, j = right; while (i < j) { while (j > i && arr[j] >= baseVal) { j--; } while (i < j && arr[i] <= baseVal) { i++; } [arr[i], arr[j]] = [arr[j], arr[i]]; } [arr[baseId], arr[i]] = [arr[i], arr[baseId]]; quickSort(arr, left, i - 1); quickSort(arr, i + 1, right); return arr; }
取基準值為最右邊的數
function quickSort(arr, left = 0, right = arr.length - 1) { if (left >= right) return; // 如果左邊的索引大於等於右邊的索引說明整理完畢 var baseVal = arr[right], // 取無序陣列最後一個數為基準值 i = left, j = right; while (i < j) { // 把所有比基準值小的數放在左邊,比基準值大的數放在右邊 while (i < j && arr[i] < baseVal) { // 找到一個比基準值大的數交換 i++; } arr[j] = arr[i]; // 將較大的值放在右邊如果沒有比基準值大的數就是將自己賦值給自己(i 等於 j) while (j > i && arr[j] > baseVal) { // 找到一個比基準值小的數交換 j--; } arr[i] = arr[j]; // 將較小的值放在左邊如果沒有找到比基準值小的數就是將自己賦值給自己(i 等於 j) } arr[i] = baseVal; // 將基準值放至中央位置完成一次迴圈(這時候 j 等於 i ) quickSort(arr, left, i - 1); // 將左邊的無序陣列重複上面的操作 quickSort(arr, i + 1, right); // 將右邊的無序陣列重複上面的操作 return arr; }
取基準值為陣列最中間的數
方法一:
function quickSort(arr, left, right) { if (left < right) { var mid = arr[parseInt((left + right) / 2)], //樞紐選擇的是中間的 l = left, r = right; while (true) { while (arr[l] < mid) { l++; } while (arr[r] > mid) { r--; } if (l >= r) { break; } [arr[l], arr[r]] = [arr[r], arr[l]]; } quickSort(arr, left, l - 1); quickSort(arr, l + 1, right); } return arr; }
方法二:
function quickSort(arr) { if (arr.length <= 1) { return arr; } var pivotIndex = Math.floor(arr.length / 2); var pivot = arr.splice(pivotIndex, 1)[0]; var left = []; var right = []; for (let i = 0; i < arr.length; i++) { if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat([pivot], quickSort(right)); }
六,並歸排序
function mergeSort(arr) { // 採用自上而下的遞迴方法 var len = arr.length; if (len < 2) { return arr; } var middle = Math.floor(len / 2), left = arr.slice(0, middle), right = arr.slice(middle); return merge(mergeSort(left), mergeSort(right)); } function merge(left, right) { var result = []; while (left.length && right.length) { if (left[0] <= right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result; }
詳情→圖解並歸排序演算法
七,堆排序
//生成大頂堆 function adjustHeap(arr, i, len) { //將當前值儲存 var temp = arr[i]; //從i結點的左子結點開始,也就是2i+1處開始 for (var j = 2 * i + 1; j < len; j = 2 * j + 1) { //如果左子結點小於右子結點,j指向右子結點 if (j + 1 < len && arr[j] < arr[j + 1]) { j++; } //如果子節點大於父節點,將子節點值賦給父節點(不用進行交換)值和索引都賦值 if (arr[j] > temp) { arr[i] = arr[j]; i = j; } else { break; } } arr[i] = temp; //將temp值放到最終的位置 } function heapSort(data) { //構造大頂堆 //此時我們從最後一個非葉子結點開始,葉結點自然不用調整 ////從第一個非葉子結點從下至上,從右至左調整結構 for (var i = data.length / 2 - 1; i >= 0; i--) { adjustHeap(data, i, data.length); } // console.log(data); //交換堆頂元素與末尾元素;不算最後一個元素,重新調整堆 for (var k = data.length - 1; k > 0; k--) { //將堆頂元素與末尾元素進行交換 [data[0], data[k]] = [data[k], data[0]]; // console.log(data); //不算最後一個元素,重新對堆進行調整 adjustHeap(data, 0, k); } return data; }
詳情→圖解堆排序演算法