算法:快速排序

算法:快速排序

快速排序

  其實我第一次聽到快速排序的時候,我就很納悶,因爲不像冒泡、插入、歸併、選擇排序等等,名稱即原理!這個直接把特性用作名稱的,我就很震驚!

  咱還是直接瞅一眼百科的解釋吧!

  快速排序是冒泡排序的改進。

  快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列

  百科中解釋了快排的一趟操作是對無序數組進行分割,使其分爲左右兩半部分,左邊的都小於某個數,右邊的都大於每個數。那某個數是哪個數呢?這個就是無所謂的,隨便取一個數就好,要不就以第1個數作爲那個數吧!

  

  就像上圖這樣,一趟排序使得小於4的處於左邊,大於4的處於右邊!

一趟排序

   那一趟排序到底做了什麼呢?它具體是怎麼使得元素位置進行如圖變換的呢!

  其實也很簡單,我們之前有講過雙指針的應用,我們兩邊分別定義指針i,j。i從左到右走,負責找大於4的,j從右往左走,負責找小於4的。

  

  到找到之後,他倆所在位置的元素一交換,就使得大的值處於右邊,小的值處於左邊!

  

  接着呢,i和j繼續移動,直到他倆相遇!此時我們將當前位置與1號位置交換,就把4放在中間了!講是這麼講,但是這個過程還是有很多需要注意的地方!!!

  

接着

  一趟排序完之後呢?其實我們只是把一個元素的最終位置確定了,即4!也是就說4肯定是在這裏放,那我們還需要處理其他的,所以仍然需要對4左邊的一趟排序,對4的右邊的一趟排序!那當然直觀的看,4右邊就一個元素5所以肯定是有序的!

  那左邊132,經過一趟排序後!其實1的位置還是沒有變,1左邊沒有了,我們需要對1右邊的元素進行一趟排序!

  

  好了,對右邊進行一趟排序後,結果如下:

  

  因爲我們是分別處理的,所以我們畫的都是部分圖,最終效果就是整體有序!

  這個就是快速排序的核心思想了,我們可以簡單總結一下,我們將序列根據某個值分爲兩段,這個成爲一趟排序,此時該值的最終位置就確定了,接着再對兩段進行一趟排序,來確定兩側元素的的最終位置。每一段都要進行一趟操作,所以着很明顯是遞歸操作!我們在代碼中可以很明顯的看到!

分析一下

  快速排序的一次劃分算法從兩頭交替搜索,直到i和j重合,因此其時間複雜度是O(n);而整個快速排序算法的時間複雜度與劃分的趟數有關!

  理想的情況是,每次劃分所選擇的中間數恰好將當前序列幾乎等分,經過log2n趟劃分,便可得到長度爲1的子表。這樣,整個算法的時間複雜度爲O(nlog2n)

  最壞的情況是,每次所選的中間數是當前序列中的最大或最小元素,這使得每次劃分所得的子表中一個爲空表,另一子表的長度爲原表的長度-1。這樣,長度爲n的數據表的快速排序需要經過n趟劃分,使得整個排序算法的時間複雜度爲O(n^2)。

  當然快排也不穩定!!位於後面的元素很有可能會拍到前面,這個發生在一趟排序過程中,仔細想想!

Java實現

  理解思路後,再看代碼其實還是蠻簡單的! 

package sort;

import java.util.Arrays;

/**
 * 快速排序
 * @author mrsaber
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] arr = new int[]{4,3,2,1,5,6,7,8,3,1,3,111,22,9};
        new QuickSort().sort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    public void sort(int[] nums,int start,int end){
        if(end-start<1)
            return;
        int i = start;
        int j = end;
        while (j>i){
            while (j>=0&&j>i&&nums[j]>nums[start]){j--;}
            while (i<end&&i<j&&nums[i]<=nums[start]){i++;}
            if(i<j){
                swap(nums,i,j);
            }
        }
        swap(nums,i,start);
        sort(nums,start,i-1);
        sort(nums,i+1,end);
    }



    /**
     * 數組元素交換
     * @param nums
     * @param i
     * @param j
     */
    public void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] =temp;
    }
}

參考資料

  • 《百度百科》

 

  

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