幾種常見排序演算法的實現及執行時間對比
阿新 • • 發佈:2020-12-09
技術標籤:演算法
// 氣泡排序 function popSort(arr) { if (arr.length < 2) return arr; let n = arr.length; while (n > 1) { let exchanged = false; for (let i = 0; i < n - 1; i++) { if (arr[i] > arr[i + 1]) { exchange(arr, i, i + 1); exchanged = true; } } n--; if (!exchanged) break; } return arr; } //插入排序 function insertSort(arr) { if (arr.length < 2) return arr; let n = 1; while (n < arr.length) { let val = arr[n]; let i = n-1; for (; i>= 0; i--) { let prev = arr[i]; if (val<prev) { arr[i+1] = arr[i] }else { break; } } arr[i+1] = val; n++; } return arr; } //希爾排序 function shellSort(arr){ if (arr.length < 2) return arr; let n = arr.length; let h = 1; while(h<n/3)h=(h+1)*2-1;//Hibbard增量 while(h>=1){ for(let i = h;i<n;i++){ for(let j = i; j>=h && arr[j]<arr[j-h];j-=h){ exchange(arr,j,j-h); } } h = (h+1)/2-1; } return arr; } //歸併排序 function mergeSort(arr){ if (arr.length < 2) return arr; merge_sort(arr,0,arr.length-1); function merge_sort(arr,l,r){ if(l>=r)return; let mid = Math.floor((r-l)/2)+l; merge_sort(arr,l,mid); merge_sort(arr,mid+1,r); merge(arr,l,r,mid); } function merge(arr,l,r,mid){ let arrcopy = []; let leftIndex = l, rightIndex = mid+1; for(let i = l; i<=r;i++){ arrcopy[i] = arr[i]; } for(let i = l; i<=r;i++){ if(leftIndex>mid){ arr[i] = arrcopy[rightIndex++] }else if(rightIndex>r){ arr[i] = arrcopy[leftIndex++] }else if(arrcopy[leftIndex] <= arrcopy[rightIndex]){ arr[i] = arrcopy[leftIndex++]; }else{ arr[i] = arrcopy[rightIndex++]; } } } } //快速排序 function quickSort(arr){ if (arr.length < 2) return arr; sort(arr,0,arr.length-1); function partition(arr,l,r){ let i = l, j = r+1; let v = arr[l]; while(true){ while(arr[++i] <= v) if(i === r)break; while(arr[--j] >= v) if(j === l)break; if(i>=j)break; exchange(arr,i,j); } exchange(arr,l,j); return j; } function sort(arr,l,r){ if(l>=r) return; let j = partition(arr,l,r); sort(arr,l,j); sort(arr,j+1,r); } } function exchange(arr, i, j) { [arr[i], arr[j]] = [arr[j], arr[i]] } function generateRandomArr(n, range) { const numberRange = range || 1000; const res = []; while (n-- > 0) { res.push(Math.round((Math.random() - 0.5) * numberRange)); } return res; } //判斷陣列是否是升序的 O(n) function isASC(arr) { let n = arr.length - 1; while (n > 0) { if (arr[n] < arr[n - 1]) return false; n--; } return true; } function printUsedTime(func) { let timestamp = new Date().getTime(); func(); console.log((new Date().getTime() - timestamp)+'ms'); } let arrlength = 200000,arrRange = 20000; console.log(`被排序陣列大小:${arrlength},陣列元素取值範圍:-${arrRange/2}到+${arrRange/2}`) let arr1 = generateRandomArr(arrlength, arrRange); let arr2 = generateRandomArr(arrlength, arrRange); let arr3 = generateRandomArr(arrlength, arrRange); let arr4 = generateRandomArr(arrlength, arrRange); let arr5 = generateRandomArr(arrlength, arrRange); console.log("pop sort") printUsedTime(() => { popSort(arr1); console.log(isASC(arr1) ? "升序" : "無序"); }) console.log("insert sort") printUsedTime(() => { insertSort(arr2); console.log(isASC(arr2) ? "升序" : "無序"); }) console.log("shell sort") printUsedTime(() => { shellSort(arr3); console.log(isASC(arr3) ? "升序" : "無序"); }) console.log("merge sort") printUsedTime(() => { mergeSort(arr4); console.log(isASC(arr4) ? "升序" : "無序"); }) console.log("quick sort") printUsedTime(() => { quickSort(arr5); console.log(isASC(arr5) ? "升序" : "無序"); }) // console.log(isASC([1,-1,0,50,-50]) ? "升序" : "無序")
用大小為200000的陣列測試各個排序的執行時間消耗,結果如下:
被排序陣列大小:200000,陣列元素取值範圍:-10000到+10000
pop sort
升序
88375ms
insert sort
升序
8609ms
shell sort
升序
52ms
merge sort
升序
998ms
quick sort
升序
29ms
其中mergeSort,shellSort,quickSort都是時間複雜度為O(nLogn)的演算法,為啥mergeSort這麼慢呢?猜測可能是因為消耗的記憶體空間相對更多,有更多的資料搬移操作導致的耗時劇增。