javaScript中常見的排序方法

  之前把常見的那幾種算法看了好幾次,看的時候也手寫了一遍,可是等到過了

好幾天又給忘了,所以決定記錄下來分享一下,也方便自己以後查看?

冒泡排序

  冒泡排序是屬於交換排序的一種,通過比較相鄰的兩個數據然後進行交

換,冒泡排序的時間複雜度爲o(n^2),空間複雜度爲o(1)。

function BubbleSort(arr) { 
     for(let i=0;i<arr.length;i++){
         for(let j=0;j<arr.length-i-1;j++){
             if(arr[j]>arr[j+1]){
                 [arr[j],arr[j+1]]=[arr[j+1],arr[j]];  //交換值
             }
         }
     }
     return arr;
  }

選擇排序

  選擇排序是通過記錄下標的方式進行比較的,定義變量(index)等於當前

下標(i),循環當前下標後面的元素,如果後面的元素比當前元素大(或者小),先不着急

交換元素,只替換下標(下標交換),一次循環過後最小元素下標的位置可以確定,最

終交換當前元素(arr[i])值和最小(或最大)下標(arr[index])的值。選擇排序的時間複雜

度爲o(n^2),空間複雜度爲o(1)。

	// 選擇
    function chooseSort(arr){
        for(let i = 0;i<arr.length;i++){
           let index = i;  //記錄當前元素下標
            for(let j =i+1;j<arr.length;j++){
                if(arr[j]<arr[index]){
                    index = j;  //只交換下標
                }
            }
            [arr[i],arr[index]] = [arr[index],arr[i]]  //一次循環之後再進行交換
        }
        return arr
    }

插入排序

  插入排序默認數組第一個元素有序,從第二個元素開始從後向前進行

比較,插入排序的時間複雜度爲o(n^2)。

   //插入排序
    function insert(arr) {
        for (let i = 1; i < arr.length; i++) {
            let current = arr[i];  //記錄當前值
            let pre_index = i - 1;  //得到上一個元素下標
            while (current <= arr[pre_index] && pre_index >= 0) {  //如果下標小於0,已經到達數組開頭
                arr[pre_index + 1] = arr[pre_index];    //交換元素
                pre_index--;   //再比較下一位元素
            }
            arr[pre_index + 1] = current;
        }
        return arr;
    }

  以上這幾種的時間複雜度都是o(n^2),也比較耗費性能。下面介紹兩種時間復

雜度爲o(nlogn)的排序算法。

快速排序

  我選擇了這種方式的快排,比較好理解。還有一種 “刨坑式”的快排,那種在理

解上有點難度,它通過左右兩個指針(或變量)對應的值進行比較,然後進行交換。

  以下代碼的原理是通過數組進行排序的,遞歸的去排序左右數組。

    //快排
    function quickSort(arr) {
        if (arr.length <= 1) return arr;
        let left = [],
            middle = [arr[0]],
            right = [];
        for (let index = 1; index < arr.length; index++) {
            if (arr[index] < middle[0]) {
                left.push(arr[index])  //比它小的放到左邊
            }else {
                right.push(arr[index])  //本身一樣大的元素也放入右邊
            }
        }
          // 遞歸併連接,這一步很重要
        return quickSort(left).concat(middle, quickSort(right))
    }

歸併排序

  歸併排序主要是利用分治算法的思想,將大問題化解成小問題,最終得到

原問題的解。遞歸地把數組分割成前後兩個子數組直到數組中只有1個元素。同

時,遞歸地從兩個數組中挨個取元素,比較大小併合並。時間複雜度爲o(nlogn),空間複雜

度爲o(n)。

  // 分割成只有一個元素的數組
function Split(arr){
    if(arr.length<2) return arr;
    let mid = Math.floor(arr.length/2);  //取中間位置
    let left = arr.slice(0,mid);  //得到左邊數組
    let right = arr.slice(mid);  //得到右邊數組
    return Merge(Split(left),Split(right));
}
function Merge(left,right){
    // 合併+排序
    var result = [];
    var nl = 0;
    var nr =0;
    while(nl<left.length && nr<right.length){
        if(left[nl] < right[nr]){//按從小到大的順序排列新的組合數組
            result.push(left[nl++]);//扔進去之後迭代
        }else{
            result.push(right[nr++]);
        }
    }
    while(nl<left.length){//剩下的一股腦兒扔進去。
        result.push(left[nl++]);
    }
    while(nr<right.length){
        result.push(right[nr++]);
    }
    return result;
}

基數排序

function radixSort(arr) {
    let max_num = Math.max(...arr);
    max_len = getLengthOfNum(max_num);
    //根據最大數進行循環(確定循環次數)
    for (let digit = 1; digit <= max_len; digit++) {
        let buckets = [];
        for (let i = 0; i < 10; i++) buckets[i] = [];  //定義“桶”
        for (let i = 0; i < arr.length; i++) {
            let value= arr[i];
            let pos = getSpecifiedValue(value, digit);
            buckets[pos ].push(value);
        }
         let result = [];
         buckets.toString().split(',').forEach((val) => {
            if (val) result.push(parseInt(val))
        })
        arr = result;  //改變原數組,再次排序  重要
    }
  return arr;
}
function getLengthOfNum(num) { return (num += '').length }  //得到最大數的長度
//根據對應位置的數,如果不存在,返回0
function getSpecifiedValue(num, position) { return (num += '').split('').reverse().join('')[position - 1] || 0 }

對於基數排序可以參考基數排序詳解這篇博客,講解的比較清晰。

穩定的排序方法:冒泡排序、插入排序、基數排序、歸併排序

不穩定的排序方法:快速排序、選擇排序、堆排序、希爾排序

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