你可能不知道的快速排序:三路快排

快速排序

快速排序是什麼 快速排序是圖靈獎得主C. A. R. Hoare(1934--)於1960時提出來的。javascript

快速排序是對冒泡排序的一種改進。它的基本思想是:經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據都比另一不部分的全部數據都要小,而後再按此方法對這兩部分數據分別進行快速排序,整個排序過程能夠遞歸進行,以此達到整個數據變成有序序列。整個排序過程只須要三步:html

  • 在數據集之中,選擇一個元素做爲"基準"(pivot)。
  • 全部小於"基準"的元素,都移到"基準"的左邊;全部大於"基準"的元素,都移到"基準"的右邊。
  • 對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到全部子集只剩下一個元素爲止。

引自wikipedia 快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),一種排序算法,最先由東尼·霍爾提出。在平均情況下,排序n個項目要Ο(n log n)次比較。在最壞情況下則須要Ο(n2)次比較,但這種情況並不常見。事實上,快速排序一般明顯比其餘Ο(n log n)算法更快,由於它的內部循環(inner loop)能夠在大部分的架構上頗有效率地被實現出來。java

步驟

  1. 找到該數組的基準點(中間數),並建立兩個空數組left和right;
  2. 遍歷數組,拿出數組中的每一個數和基準點進行比較,若是比基準點小就放到left數組中,若是比基準點大就放到right數組中;
  3. 對數組left和right進行遞歸調用。

方法一

function quickSort(arr{
      if (arr.length<=1) {return arr;}
      var left = [],
        right = [],
        baseDot =Math.round(arr.length/2),
        base =arr.splice(baseDot, 1)[0];

      for (var i =0; i <arr.length; i++) {
        if (arr[i] < base) {
          left.push(arr[i])
        }else {
          right.push(arr[i])
        }
      }

      return quickSort(left).concat([base], quickSort(right));
    }

實現一個quickSort的封裝,而且定義left和right,找到數組的基準點baseDot和對應的基數base,而後遍歷數組的每一項和base進行對比,最後遞歸調用,給出一個跳出條件if (arr.length <= 1) {return arr;}web

方法二

function quickSort(array, left, right{
      var length =array.length;
        left =typeof left ==='number'? left :0,
        right =typeof right ==='number'? right : length-1;

        if (left < right) {
            var index = left -1;
            for (var i = left; i <= right; i++) {
                if (array[i] <= array[right]) {
                    index++;
                    var temp = array[index];
                    array[index] = array[i];
                    array[i] = temp;
                }
            }
            quickSort(array, left, index -1);
            quickSort(array, index +1, right);
        }
        return array;
    }

快速排序的基本思想就是分治法算法

引自wikipedia 在計算機科學中,分治法是建基於多項分支遞歸的一種很重要的算法範式。字面上的解釋是「分而治之」,就是把一個複雜的問題分紅兩個或更多的相同或類似的子問題,直到最後子問題能夠簡單的直接求解,原問題的解即子問題的解的合併。數組

快速排序的改進方法:三路快排

定義

三路快速排序是快速排序的的一個優化版本, 將數組分紅三段, 即小於基準元素、 等於 基準元素和大於基準元素, 這樣能夠比較高效的處理數組中存在相同元素的狀況,其它特徵與快速排序基本相同。微信

我這裏簡單歸納一下思路,有興趣的同窗可到上面的連接上閱讀:[快速排序及優化(Java實現)][Java]架構

  • 隨機選取基準值base(支點隨機選取),參考[快速排序算法的優化思路總結][Link 1]
  • 配合着使用插入排序(當問題規模較小時,近乎有序時,插入排序表現的很好)
  • 當大量數據,且重複數多時,用三路快排
    <!DOCTYPE html>
    <html>
    
     <head>
      <meta charset="UTF-8">
      <title></title>
      <script type="text/javascript">
       console.time("test0")
       function qSort(arr) {
        if(arr.length == 0) {
         return [];
        }
        var left = [];
        var right = [];
        var pivot = arr[0];
        for(var i = 1; i < arr.length; i++) { // 注意這裏的起始值,由於有一個做爲flag了
         if(arr[i] < pivot) {
          left.push(arr[i]);
         } else {
          right.push(arr[i]);
         }
        }
        return [...qSort(left), pivot, ...qSort(right)];
       }
       console.log(qSort([9, 4, 10, 3, 1, 1, 0, 10, 8, 3, 9, 9, 4, 10, 10, 9, 9, 9, 1, 0]));
       console.timeEnd("test0")
      </script>
      <script type="text/javascript">
       console.time("test1")
       function qSort3(arr) {       //三路快排
        if(arr.length == 0) {
         return [];
        }
        var left = [];
        var center = [];
        var right = [];
        var pivot = arr[0];    //偷懶,直接取第一個,實際取值狀況 參考[快速排序算法的優化思路總結]
        for(var i = 0; i < arr.length; i++) {      
         if(arr[i] < pivot) {
          left.push(arr[i]);
         } else if(arr[i] == pivot) {
          center.push(arr[i]);
         } else {
          right.push(arr[i]);
         }
        }
        return [...qSort3(left), ...center, ...qSort3(right)];
       }
       console.log(qSort3([9, 4, 10, 3, 1, 1, 0, 10, 8, 3, 9, 9, 4, 10, 10, 9, 9, 9, 1, 0]))
       console.timeEnd("test1")
      </script>
     </head>
    
     <body>
     </body>
    
    </html>

能夠看到對有重複數據的數據優化仍是很可觀的。編輯器


本文分享自微信公衆號 - JavaScript忍者祕籍(js-obok)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。oop

相關文章
相關標籤/搜索