《算法導論》讀書筆記之第7章 快速排序


  本章介紹了快速排序及其算法分析,快速排序采用的是分治算法思想,對包含n個數的輸入數組,最壞情況下運行時間為θ(n^2),但是平均性能相當好,期望的運行時間為θ(nlgn)。另外快速排序能夠就地排序(我理解是不需要引入額外的輔助空間,每次划分能確定一個元素的具體位置),在虛擬環境中能很好的工作。

1、快速排序的描述

  快速排序算法采用的分治算法,因此對一個子數組A[p…r]進行快速排序的三個步驟為:

  (1)分解:數組A[p...r]被划分為兩個(可能為空)子數組A[p...q-1]和A[q+1...r],給定一個樞軸,使得A[p...q-1]中的每個元素小於等於A[q],A[q+1...r]中的每個元素大於等於A[q],q下標是在划分過程中計算得出的。

  (2)解決:通過遞歸調用快速排序,對子數組A[p...q-1]和A[q+1...r]進行排序。

  (3)合並:因為兩個子數組是就地排序,不需要合並操作,整個數組A[p…r]排序完成。

  快速排序關鍵過程是對數組進行划分,划分過程需要選擇一個主元素(pivot element)作為參照,圍繞着這個主元素進划分子數組。舉個列說明如何划分數組,現有子數組A={24,15,27,5,43,87,34},以最后一個元素為主元素進行划分,划分過程如圖所示:

書中給出了划分過程的偽代碼:

1 PARTITION(A,p,r)
2    x = A[r]   //將最后一個元素作為主元素
3   i = p-1
4    for j=p to r-1     //從第一個元素開始到倒數第二個元素結束,比較確定主元的位置
5        do if A[j] <= x
6              i = i+1
7              exchange A[i] <-> A[j]
8    exchange A[i+1]<->A[r]   //最終確定主元的位置
9    return i+1   //返回主元的位置

根據划分過程的為代碼,書中又給出了快速排序的為代碼:

1 QUICKSORT(A,p,r)
2     if p<r
3        q = PARTITION(A,p,r)    //確定划分位置
4        QUICKSORT(A,p,q-1)     //子數組A[p...q-1]
5        QUICKSORT(Q,q+1,r)     //子數組A[q+1...r]

 采用C元素實現一個完成的快速排序程序,程序如下:

View Code
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 size_t partition(int* datas,int beg,int last);
 5 void quick_sort(int* datas,int beg,int last);
 6 void swap(int *a,int *b);
 7 
 8 int main()
 9 {
10     size_t i;
11     int datas[10] = {78,13,9,23,45,14,35,65,56,79};
12     printf("After quick sort,the datas is:\n");
13     quick_sort(datas,0,9);
14     for(i=0;i<10;++i)
15         printf("%d ",datas[i]);
16     exit(0);
17 }
18 
19 void swap(int *a,int *b)
20 {
21     int temp = *a;
22     *a = *b;
23     *b = temp;
24 }
25 
26 size_t partition(int* datas,int beg,int last)
27 {
28     int pivot = datas[last];
29     int i,j;
30     i = beg -1;
31     for(j=beg;j<last;j++)
32     {
33         if(datas[j] < pivot)
34         {
35             i = i+1;
36             swap(datas+i,datas+j);
37         }
38     }
39     swap(datas+i+1,datas+last);
40     return (i+1);
41 }
42 void quick_sort(int* datas,int beg,int last)
43 {
44     int pivot;
45     if(beg < last)
46     {
47         pivot = partition(datas,beg,last);
48         quick_sort(datas,beg,pivot-1);
49         quick_sort(datas,pivot+1,last);
50     }
51 
52 }

程序測試結果如下:

 可以將划分過程之間嵌入到快速排序過程中,C語言實現如下所示:

 1 void quicksort(int *datas,int length)
 2 {
 3     int pivot ,i,j;
 4     if(length > 1)
 5     {
 6         pivot = datas[length-1];
 7         for(i=0,j=0;j<length-1;j++)
 8         {
 9             if(datas[j] < pivot)
10             {
11                 swap(datas+i,datas+j);
12                 i = i+1;
13             }
14         }
15         swap(datas+i,datas+length-1);
16         quicksort(datas,i);
17         quicksort(datas+i,length-i);
18     }
19 }

2、快速算法排序的性能
  最快情況划分:當划分過程中產生的兩個區域分別包含n-1個元素和1個元素的時候(即將待排序的數是逆序的),這樣第個調用過程中每次划分都是不對稱的。算法時間遞歸的表示為:T(n)=T(n-1)+T(o)+θ(n) = T(n-1)+θ(n) = θ(n^2)。例如下面的情況:

  最佳情況划分:每次划分達到兩個子問題的大小不可能都打大於n/2,當划分后一個兩個子問題的大小分別為n/2(下取整)n/2(上取整數)-1時候,快速排序時間最佳,這時候運行時間遞歸式為:T(n)<=2 T(n/2)+θ(n) = O(nlgn)。例如下面的情況:

3、快速排序的隨機化版本

  前面快速排序在划分的時候總是以最后一個元素作為主元進行划分的,此時可以改用隨機獲取一個主元素,獲得較好的評價功能。可以調用隨機函數獲取隨機的主元素,然后進行划分。書中給出了為代碼如下:

1 RANDOMIZED-PARTITION(A,p,r)
2    i = RANDOM(p,r)
3    exchange A[r] <->A[j]
4    return PARTITION(A,p,r)

 


免責聲明!

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



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