白話排序算法--快速排序


前言:

  寫到快速排序時,之前已經進行了冒泡、選擇、插入排序,發現算法問題很多東西都是和實際問題相逆的,實際你可能會由外及里,由上及下,可是算法里面它有時就需要你由里往外去擴散,好比最里面的是小成果,然后一次次往外變化,成果也慢慢變大,最后直至達到最終成果為止。本篇快速排序方法因為調用了遞歸,你就可以逆着由里及外來思考問題。  寫這篇文章光畫圖就花費了我2小時時間,越抽象就越不好形容和比喻,畫的不好,希望各位不要吐槽。

快速排序:先快速排序將隊列一分為二,然后對每個隊列進行遞歸調用快速排序方法,直至不能再次分解后依次返回成果。


 情景描述:

  緊接選擇排序情景,有一天,被同學稱為大濕的體育老師胃疼請假休息了,真好數學老師閑着就來代課了,同樣要排列隊形,但是數學老師牛了,說同學們,我今天教你們一種快速排序的方法,到時候來了別忘了教你們的體育老師哦(體育老師估計胃更疼了...)

一、

  1.  我們就把第一個同學當做基數,其他同學和他進行比較,期間,基數不變,此時基數同學站出來,留下了個空位
  2.  首先從最后一個同學開開始,依次向前和基數進行比較,第一個比基數同學等高或者矮了,就站到基數的位置,自己的位置又空下了
  3.  步驟2后,我們再從第一位依次向后和基數比較,如果等於或者比基數高,就站到步驟二留下的空位,自己位置空出來
  4.    排除前后已經換過位置的同學,重復步驟2和3, 依次和基數比較,然后坐入空位,留下新空位   
  5.    直到都和基數進行比較過,然后基數同學站到最后的空位里面

二、

  1.    通過步驟一我們把要排列的隊分為了兩隊,而兩隊之內還是高低不齊的
  2.    首先來排前面的,讓前面的隊依舊以第一個為基數,結尾到分割線同學的前一位,執行步驟一
  3.    接着排后面的,以分割線同學的后一位為開始,隊列末尾為結束,執行步驟一
  4. 重復執行步驟2和3,直至不能再拆分即排列完成

步驟一圖解

上圖為一輪快速排序方法


 步驟二圖解

上圖為依次遞歸調用快速排序方法,對每次的新隊列進行快速排序


代碼片段

/**
     * 快速排序,返回一個中軸下標
     * @param arr
     * @param low    隊列起始下標
     * @param high    隊列結束下標
     * @return
     */
    public int quickSort(int[] arr, int low, int high) {
        int tmp = arr[low]; // 數組的第一個作為中軸
        
        while (low < high) {
            while (low < high && arr[high] >= tmp) {
                high--;
            }
            arr[low] = arr[high]; // 比中軸小的記錄移到低端
            
            while (low < high && arr[low] <= tmp) {
                low++;
            }
            arr[high] = arr[low]; // 比中軸大的記錄移到高端
        }

        arr[low] = tmp; // 中軸記錄到尾
        return low; // 返回中軸的位置
    }
    
    /** 遞歸調用快速排序方法,對數組進行排序 **/
    public void _quickSort(int[] list, int low, int high) {
        if (low < high) {
            int middle = quickSort(list, low, high); // 獲得中軸下標
            // 對前部分進行排序,遞歸進行,此時不會執行后半部分,直至不能再次拆分,再依次執行下半部分
            _quickSort(list, low, middle - 1);
            // 對下半部分進行排序
            _quickSort(list, middle + 1, high); 
        }
    }

  代碼挺少,但是沒圖的話理解起來太抽象了,還得邊拿筆畫着邊執行着,完了才領悟了其原理。

再來嚴謹的總結下步驟:

  1. 設置兩個變量i、j,排序開始的時候:i=0,j=N-1
  2. i開始向后搜索,即由前開始向后搜索(i ++ ),找到第一個大於keyA[i]A[i]A[j]交換
  3. j開始向前搜索,即由后開始向前搜索(j -- ),找到第一個小於key的值A[j]A[i]A[j]交換
  4. i開始向后搜索,即由前開始向后搜索(i ++ ),找到第一個大於keyA[i]A[i]A[j]交換
  5. 重復第345步,直到 I=J (3,4步是在程序中沒找到時候j=j-1i=i+1,直至找到為止。找到並交換的時候i j指針位置不變。另外當i=j這過程一定正好是i+j-完成的最后令循環結束

優點:速度快,適合基本無序的隊列

缺點:多個相同的值的相對位置也許會在算法結束時產生變動,所以不穩定,還有借用了遞歸思想,數據大量時消耗內存

  終於寫完了,洗洗睡了:) ,最后把這幾天的排序整合下:

 

                              寫作不易,難免有疏漏和錯誤,還請慷慨指正,不錯請推薦

  ps:歡迎轉載,轉載請注明出處:http://www.cnblogs.com/liuyitian/p/4077624.html


                                        每天多學一點點     代碼少敲一點點


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM