十大排序算法(JavaScript語言)

一:冒泡排序

動圖理解

在這裏插入圖片描述

代碼實現
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);
    }
}
// 在當前增量爲gap的分組情況下,把索引爲i的元素插入至正確位置。
function shellSortHelp(arr,i,gap){
    let insert_index = i;
    let insert_ele = arr[i];
    // 找到插入位置(間隔爲gap)
    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){
        // 1.分治分組時,索引中值二分
        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()// 借用到拷貝數組,空間複雜度O(n)
    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
        }
        // 2.合併比較時,先判斷取左邊數組元素,結合1判斷 歸併排序穩定
        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){
        //arr[pointerLeft]爲坑位
        while(pointerLeft<pointerRight && arr[pointerRight]>referNum){
            pointerRight--;
        }
        if(pointerLeft<pointerRight){
            arr[pointerLeft] = arr[pointerRight];
        }
        //arr[pointerRight]爲坑位
        while(pointerLeft<pointerRight && arr[pointerLeft]<referNum){
            pointerLeft++;
        }
        if(pointerLeft<pointerRight){
            arr[pointerRight] = arr[pointerLeft];
        }
    }
    //pointerLeft==pointerRight,使用基準數佔住坑位
    arr[pointerLeft] = referNum;
    // 返回邏輯中間值索引,此時arr[x]<arr[pointerLeft]<arr[y]。(x<pointerLeft<y)
    return pointerLeft;
}
算法分析
  • 平均時間複雜度【時間】:O(nlogn)
  • 最好情況【時間】:O(nlogn)
  • 最壞情況【時間】:O(n2)
  • 空間複雜度【空間】:O(nlogn)
  • 排序方式【空間】:內排序
  • 穩定性【空間】:不穩定(索引邏輯中值二分)

七:堆排序

動圖理解

在這裏插入圖片描述

代碼實現
// 1.堆排序
let len = 0// heapSort和heapAdjust方法共享。
function heapSort(arr){
    buildMaxHelp(arr)
    for(let i=arr.length-1;i>0;i--){
        swap(arr,0,i)
        len--
        heapAdjust(arr,0)
    }
}
// 2.構建大頂堆
function buildMaxHelp(arr){
    len = arr.length
    // 堆數組:索引爲[0,Math.floor(arr.length)-1]的爲非葉子結點。
    for(let i=Math.floor(arr.length/2)-1;i>=0;i--){
        heapAdjust(arr,i)
    }
}
// 3.堆調整:調整爲以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]){ // 排序已提出的元素不參與構建堆,此處len不能爲arr.length
        largest = right
    }
    if(left<len && arr[left]>arr[largest]){
        largest = left
    }
    if(largest!=i){
        swap(arr,i,largest)
        heapAdjust(arr,largest)// 堆變化後,遞歸調整子堆
    }
}
// 4.元素交換
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--){// 只需遍歷到arr.length-k即可
        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)
  • 排序方式【空間】:外排序
  • 穩定性【空間】:穩定(計數排序不基於元素的比較,此處穩定不指上述未優化的計數排序代碼)。

九:桶排序

十:基數排序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章