一:冒泡排序
動圖理解
代碼實現
function bubbleSort(arr){
for(let i=0;i<arr.length-1;i++){
let didSwap = false;
for(let j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
didSwap = true;
}
}
if(!didSwap){
break;
}
}
}
算法分析
- 平均時間複雜度【時間】:O(n2)
- 最好情況【時間】:O(n),發生在數組本身有序的情況下。
- 最壞情況【時間】:O(n2) ,發生在數組本身反序的情況下。
- 空間複雜度【空間】:O(1) ,僅在原數組空間下進行元素交換。
- 排序方式【空間】:內排序
- 穩定性【空間】:穩定
二:選擇排序
動圖理解
代碼實現
function selectSort(arr){
for(let i=0;i<arr.length-1;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
算法分析
- 平均時間複雜度【時間】:O(n2)
- 最好情況【時間】:O(n2)
- 最壞情況【時間】:O(n2)
- 空間複雜度【空間】:O(1),僅在原數組空間下進行元素交換。
- 排序方式【空間】:內排序
- 穩定性【空間】:不穩定(如 [5a,8,5b,2,9],第一輪選擇交換後爲[2,8,5b,5a,9],兩個5前後順序變化了)。
三:插入排序
動圖理解
代碼實現
function insertSort(arr){
for(let i=1;i<arr.length;i++){
let insert_index = i;
let insert_ele = arr[i];
for(let j=i-1;j>=0;j--){
if(insert_ele<arr[j]){
insert_index = j;
}else{
break;
}
}
for(let z=i-1;z>=insert_index;z--){
arr[z+1] = arr[z];
}
arr[insert_index] = insert_ele;
}
}
算法分析
- 平均時間複雜度【時間】:O(n2)
- 最好情況【時間】:O(n),發生在數組本身有序情況下,每個元素(除第一個元素外)都比一次挪一次插一次。
- 最壞情況【時間】:O(n2),發生在數組本身無序情況下。
- 空間複雜度【空間】:O(1),僅在原數組空間下進行元素交換。
- 排序方式【空間】:內排序
- 穩定性【空間】:穩定
四:希爾排序
動圖理解
代碼實現
function shellSort(arr){
let gap = Math.floor(arr.length/2);
while(gap>=1){
for(let i=gap;i<arr.length;i++){
shellSortHelp(arr,i,gap);
}
gap = Math.floor(gap/2);
}
}
function shellSortHelp(arr,i,gap){
let insert_index = i;
let insert_ele = arr[i];
for(let j=i-gap;j>=0;j=j-gap){
if(insert_ele<arr[j]){
insert_index = j;
}else{
break
}
}
for(let z=i-gap;z>=insert_index;z=z-gap){
arr[z+gap] = arr[z];
}
arr[insert_index] = insert_ele;
}
算法分析
- 平均時間複雜度【時間】:O(nlog2 n)
- 最好情況【時間】:O(nlog2 n)
- 最壞情況【時間】:O(nlog2 n)
- 空間複雜度【空間】:O(1),僅在原數組空間下進行元素交換。
- 排序方式【空間】:內排序
- 穩定性【空間】:不穩定(如 [5a,5b,2,9],第一次分組交換後爲[2,5b,5a,9],第二次分組順序不變,兩個5前後順序變化了)
五:歸併排序
動圖理解
代碼實現
function mergeSort(arr,left,right) {
if(left<right){
let center = Math.floor((left+right)/2)
mergeSort(arr,left,center)
mergeSort(arr,center+1,right)
mergeSortHelp(arr,left,right,center)
}
}
function mergeSortHelp(arr,left,right,center) {
let pointer_left = left
let pointer_right = center+1
let arr_copy = arr.slice()
for(let i=left;i<=right;i++){
if(pointer_left===center+1){
for(let j=i;j<=right;j++){
arr[j] = arr_copy[pointer_right++]
}
break
}
else if(pointer_right===right+1){
for(let j=i;j<=right;j++){
arr[j] = arr_copy[pointer_left++]
}
break
}
else if(arr_copy[pointer_left]<=arr_copy[pointer_right]){
arr[i] = arr_copy[pointer_left++]
}
else{
arr[i] = arr_copy[pointer_right++]
}
}
}
算法分析
- 平均時間複雜度【時間】:O(nlogn)
- 最好情況【時間】:O(nlogn)
- 最壞情況【時間】:O(nlogn)
- 空間複雜度【空間】:O(n),會使用到拷貝數組。
- 排序方式【空間】:外排序
- 穩定性【空間】:穩定。
六:快速排序
動圖理解
代碼實現
function quickSort(arr,left,right){
if(left<right){
let loginMid = arrAdjust(arr,left,right);
quickSort(arr,left,loginMid-1);
quickSort(arr,loginMid+1,right);
}
}
function arrAdjust(arr,left,right){
let pointerLeft = left;
let pointerRight = right;
let referNum = arr[pointerLeft];
while (pointerLeft<pointerRight){
while(pointerLeft<pointerRight && arr[pointerRight]>referNum){
pointerRight--;
}
if(pointerLeft<pointerRight){
arr[pointerLeft] = arr[pointerRight];
}
while(pointerLeft<pointerRight && arr[pointerLeft]<referNum){
pointerLeft++;
}
if(pointerLeft<pointerRight){
arr[pointerRight] = arr[pointerLeft];
}
}
arr[pointerLeft] = referNum;
return pointerLeft;
}
算法分析
- 平均時間複雜度【時間】:O(nlogn)
- 最好情況【時間】:O(nlogn)
- 最壞情況【時間】:O(n2)
- 空間複雜度【空間】:O(nlogn)
- 排序方式【空間】:內排序
- 穩定性【空間】:不穩定(索引邏輯中值二分)
七:堆排序
動圖理解
代碼實現
let len = 0
function heapSort(arr){
buildMaxHelp(arr)
for(let i=arr.length-1;i>0;i--){
swap(arr,0,i)
len--
heapAdjust(arr,0)
}
}
function buildMaxHelp(arr){
len = arr.length
for(let i=Math.floor(arr.length/2)-1;i>=0;i--){
heapAdjust(arr,i)
}
}
function heapAdjust(arr,i){
let left = 2*i+1
let right = 2*i+2
let largest = i
if(right<len && arr[right]>arr[largest]){
largest = right
}
if(left<len && arr[left]>arr[largest]){
largest = left
}
if(largest!=i){
swap(arr,i,largest)
heapAdjust(arr,largest)
}
}
function swap(arr,i,j){
let temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
- 騰訊筆試題:無序不重複的數字,取出第K大的數字(取出第k小的數字用小頂堆)。
function heapsort2(arr,k){
buildMaxHeap(arr)
for(let i=arr.length-1;i>=arr.length-k;i--){
swap(arr,0,i)
len--
heapify(arr,0)
}
return arr[arr.length-k]
}
算法分析
- 平均時間複雜度【時間】:O(nlogn)
- 最好情況【時間】:O(nlogn)
- 最壞情況【時間】:O(nlogn)
- 空間複雜度【空間】:O(1)
- 排序方式【空間】:內排序
- 穩定性【穩定性】:不穩定
八:計數排序
動圖理解
代碼實現
function countingSort(arr,max = Math.max(...arr)){
let bucketArr = new Array(max+1)
for(let i=0;i<arr.length;i++){
if(!bucketArr[arr[i]]){
bucketArr[arr[i]] = 0
}
bucketArr[arr[i]]+=1
}
let pointer = 0
for(let j=0;j<bucketArr.length;j++){
while (bucketArr[j]-->0){
arr[pointer++]=j
}
}
}
算法分析
- 平均時間複雜度【時間】:O(n+k)。(n=arr.length,k=bucket.length)
- 最好情況【時間】:O(n+k)
- 最壞情況【時間】:O(n+k)
- 空間複雜度【空間】:O(k)
- 排序方式【空間】:外排序
- 穩定性【空間】:穩定(計數排序不基於元素的比較,此處穩定不指上述未優化的計數排序代碼)。
九:桶排序
十:基數排序