排序圖解:js排序演算法實現
之前寫過js實現陣列去重, 今天繼續研究陣列: 排序演算法實現。 排序是資料結構主要內容,並不限於語言主要在於思想;大學曾經用C語言研究過一段時間的排序實現, 這段時間有空用JS再將排序知識點熟悉一遍。
理解排序不得不提的是日本人實現的一個排序動畫站, 該站對於研究排序大有益處。當然本文的排序演算法並不與其一致, 本文是9種js排序實現**的實踐與完善: 理解其9種演算法然後使每種演算法程式碼均能正常執行。
1.插入排序
最普通的排序演算法, 從陣列下標1開始每增1項排序一次,越往後遍歷次數越多;
原理圖:
程式碼:
// 插入排序 從下標1開始每增1項排序一次,越往後遍歷次數越多
function sort1(array) {
var len = array.length,
i, j, tmp, result;
// 設定陣列副本
result = array.slice(0);
for(i=1; i < len; i++){
tmp = result[i];
j = i - 1;
while(j>=0 && tmp < result[j]){
result[j+1] = result[j];
j--;
}
result[j+1] = tmp;
}
return result;
}
2.二分插入排序
插入排序的一種優化實現, 通過二分法減少遍歷時間。
原理圖:
程式碼:
// 先在有序區通過二分查詢的方法找到移動元素的起始位置,
// 然後通過這個起始位置將後面所有的元素後移
function sort2(array) {
var len = array.length,
i, j, tmp, low, high, mid, result;
// 賦予陣列副本
result = array.slice(0);
for(i = 1; i < len; i++){
tmp = result[i];
low = 0;
high = i - 1;
while(low <= high){
mid = parseInt((low + high)/2, 10);
if(tmp < result[mid]) high = mid - 1;
else low = mid + 1;
}
for(j = i - 1; j >= high+1; j--){
result[j+1] = result[j];
}
result[j+1] = tmp;
}
return result;
}
3.希爾排序
其排序思路有點複雜, 需花多點時間理解;排序思路:先將整個待排序記錄序列分割成若干個子序列,在序列內分別進行直接插入排序,待整個序列基本有序時,再對全體記錄進行一次直接插入排序。
原理圖:
程式碼:
// 希爾排序:先將整個待排序記錄序列分割成若干個子序列
// 在序列內分別進行直接插入排序,待整個序列基本有序時,
// 再對全體記錄進行一次直接插入排序
function sort3(array){
var len = array.length, gap = parseInt(len/2),
i, j, tmp, result;
// 複製陣列
result = array.slice(0);
while(gap > 0){
for(i = gap; i < len; i++){
tmp = result[i];
j = i - gap;
while(j>=0 && tmp < result[j]){
result[j + gap] = result[j];
j = j - gap;
}
result[j + gap] = tmp;
}
gap = parseInt(gap/2);
}
return result;
}
4.氣泡排序
很常見很容易理解的排序演算法, 排序思路:遍歷陣列,每次遍歷就將最大(或最小)值推至最前。越往後遍歷查詢次數越少, 跟插入排序剛好相反。
原理圖:
程式碼:
// 氣泡排序 每次將最小元素推至最前
function sort4(array) {
var len = array.length,
i, j, tmp, result;
result = array.slice(0);
for (i = 0; i < len; i++) {
for (j = len - 1; j > i; j--) {
if (result[j] < result[j - 1]) {
tmp = result[j - 1];
result[j - 1] = result[j];
result[j] = tmp;
}
}
}
return result;
}
5.改進氣泡排序
對上述氣泡排序的一種優化, 優化思路:當一次遍歷前後陣列不產生變化時,說明該陣列已經有序,結束排序。
原理圖:
程式碼:
// 如果在某次的排序中沒有出現交換的情況,
// 那麼說明在無序的元素現在已經是有序了,就可以直接返回了。
function sort5(array) {
var len = array.length,
i, j, tmp, exchange, result;
result = array.slice(0);
for (i = 0; i < len; i++) {
exchange = 0;
for (j = len - 1; j > i; j--) {
if (result[j] < result[j - 1]) {
tmp = result[j];
result[j] = result[j - 1];
result[j - 1] = tmp;
exchange = 1;
}
}
if (!exchange) return result;
}
return result;
}
6.快速排序
快速排序在諸多演算法排序中可能不是最好的, 但個人認為在JS語言實現中是最快的!以前公司專案中對比過二分插入排序、優化氣泡排序、快速排序的JS實現執行時間,幾千條資料的陣列在firefox下快速排序的速度比冒泡、插入排序快3至4秒(陣列元素為複雜的物件,根據物件某一屬性值排序)。阮一峰老師研究JS實現排序時曾只針對該種排序進行講解:javascript的快速排序實現**。
原理圖:
程式碼:
//(1)在資料集之中,選擇一個元素作為"基準"(pivot)。
//(2)所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。
//(3)對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到所有子集只剩下一個元素為止。
function sort6(array) {
var tmp_array = array.slice(0), result,
quickSort = function(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 (var 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));
};
result = quickSort(tmp_array);
return result;
}
7.選擇排序
實現思路跟氣泡排序差不多, 可以說是氣泡排序的衍生版本;
原理圖:
程式碼:
// 在無序區中選出最小的元素,然後將它和無序區的第一個元素交換位置。
// 原理跟氣泡排序一樣,算是冒泡的衍生版本
function sort7(array) {
var len = array.length,
i, j, k, tmp, result;
result = array.slice(0);
for (i = 0; i < len; i++) {
k = i;
for (j = i + 1; j < len; j++) {
if (result[j] < result[k]) k = j;
}
if (k != i) {
tmp = result[k];
result[k] = result[i];
result[i] = tmp;
}
}
return result;
}
8.堆排序
因為js模擬二叉樹比較麻煩,所以堆排序的優勢用js語言無法體現, 相對而言C語言的連結串列在實現上更能表現堆排序,堆排序或許更適合指標類的計算機語言。本文注重圖解各排序的基本思路,所以該排序的具體實現沒講太細, 如想深究實現細節請看:堆排序及其分析**。
原理圖:
1.調整二叉樹,形成大根堆(子節點都比父節點小)。
2.交換堆第一元素跟最後元素位置,最後元素彈出堆。然後繼續回到1,調整堆。
3.重複2, 當所有節點彈出堆後;彈出的節點值就是有序的了。
程式碼:
// 1) 初始堆:將原始陣列調整成大根堆的方法——篩選演算法:子節點都比父節點小
// 2) 堆排序: 每次將堆頂元素與陣列最後面的且沒有被置換的元素互換。
// 參考程式碼: http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/
function sort8(array) {
var result = array.slice(0);
function swap(array, i, j) {
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
function maxHeapify(array, index, heapSize) {
var iMax, iLeft, iRight;
while (true) {
iMax = index;
iLeft = 2 * index + 1;
iRight = 2 * (index + 1);
if (iLeft < heapSize && array[index] < array[iLeft]) {
iMax = iLeft;
}
if (iRight < heapSize && array[iMax] < array[iRight]) {
iMax = iRight;
}
if (iMax != index) {
swap(array, iMax, index);
index = iMax;
} else {
break;
}
}
}
function buildMaxHeap(array) {
var i, iParent = Math.floor(array.length / 2) - 1;
for (i = iParent; i >= 0; i--) {
maxHeapify(array, i, array.length);
}
}
function sort(array) {
buildMaxHeap(array);
for (var i = array.length - 1; i > 0; i--) {
swap(array, 0, i);
maxHeapify(array, 0, i);
}
return array;
}
return sort(result);
}
9.歸併排序
很容易理解且執行效率一般(js實現)的排序, 排序思路:將無序的陣列 拆成N部分進行有序處理,然後合併;
原理圖:
程式碼:
// 合併排序:將無序的陣列 拆成N部分進行有序處理,然後合併;
// 參考程式碼: https://gist.github.com/paullewis/1982121
function sort9(array) {
var result = array.slice(0);
// 遞迴呼叫合併函式
function sort(array) {
var length = array.length,
mid = Math.floor(length * 0.5),
left = array.slice(0, mid),
right = array.slice(mid, length);
if (length === 1) {
return array;
}
return merge(sort(left), sort(right));
}
// 合併 兩有序的陣列
function merge(left, right) {
var result = [];
while (left.length || right.length) {
if (left.length && right.length) {
if (left[0] < right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
} else if (left.length) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
return result;
}
return sort(result);
}
本文程式碼:
demo原始碼
參考文章:
1.排序動畫站;
2.9種js排序實現;
3.阮一峰:javascript的快速排序實現;
4.堆排序及其分析;
5.常見排序演算法;
6.github: paullewis 歸併演算法實現。
相關文章
- js實現兩種實用的排序演算法——冒泡、快速排序JS排序演算法
- js排序演算法原理圖示詳解JS排序演算法
- 排序演算法:Java實現希爾排序排序演算法Java
- 圖解排序演算法圖解排序演算法
- 排序演算法-Java實現快速排序演算法排序演算法Java
- js 實現堆排序JS排序
- 排序演算法之快速排序的實現排序演算法
- 圖解JavaScript演算法排序圖解JavaScript演算法排序
- 圖解堆排序演算法圖解排序演算法
- 圖解氣泡排序及演算法優化(Java實現)圖解排序演算法優化Java
- 圖解選擇排序及演算法優化(Java實現)圖解排序演算法優化Java
- 排序演算法分析總結(附js實現)排序演算法JS
- python排序演算法的實現-快速排序Python排序演算法
- 圖解拓撲排序+程式碼實現圖解排序
- 演算法圖解之快速排序演算法圖解排序
- 排序演算法 Java實現排序演算法Java
- 排序演算法Java實現排序演算法Java
- 用JS實現氣泡排序和插入排序JS排序
- python實現氣泡排序、插入排序以及快速排序演算法Python排序演算法
- 圖的拓撲排序詳解與實現排序
- 用原生Js利用sort方法 實現圖片的正 倒排序和隨機排序JS排序隨機
- JavaScript實現常用排序演算法JavaScript排序演算法
- 【演算法】希爾排序的實現演算法排序
- 快速排序(quicksort)演算法實現排序UI演算法
- 常見排序演算法原理及JS程式碼實現排序演算法JS
- JS的各種排序演算法實現--暫時不懂JS排序演算法
- 圖形化排序演算法比較:快速排序、插入排序、選擇排序、氣泡排序排序演算法
- js排序演算法整理JS排序演算法
- 【排序演算法動畫解】排序介紹及氣泡排序排序演算法動畫
- js實現資料結構及演算法之排序演算法JS資料結構演算法排序
- Python八大演算法的實現,插入排序、希爾排序、氣泡排序、快速排序、直接選擇排序、堆排序、歸併排序、基數排序。Python演算法排序
- 原生js實現商品排序功能JS排序
- 圖解快速排序圖解排序
- 【演算法】演算法圖解筆記_快速排序演算法圖解筆記排序
- 「排序演算法」圖解雙軸快排排序演算法圖解
- 演算法-排序演算法思想及實現演算法排序
- JavaScript實現經典排序演算法JavaScript排序演算法
- 快速排序演算法C++實現排序演算法C++