C++分治策略實現快速排序


問題描述:

        給定一個未知順序的n個元素組成的數組,現要利用快速排序算法對這n個元素進行非遞減排序

細節須知:

(1)代碼實現了利用遞歸對數組進行快速排序,其中limit為從已有的隨機數文件中輸入的所要進行排序的數據的數量(生成隨機數並寫入文件的過程已在前篇中寫出)。

(2)算法主要利用哨兵元素對數據進行分塊遞歸無限細分之后實現排序。

(3)代碼同樣利用clock函數對算法的執行時間進行計算以進行算法的效率評估

(4)為了驗證排序結果,代碼實現了將排序后的內容輸出到同文件夾下的sort_number.txt文件中。

算法原理:

        它的完成過程主要是將數組分解為兩部分,然后分別對每一部分排序。在划分數組時,是將所有小於某個哨兵元素的項目放到該項目之前,將所有大於該哨兵元素的項目放到該項目之后。哨兵元素可以是任意項目,為方便起見,通常直接選擇第一個項目。因而可以總結為三步:(1)分解;(2)遞歸求解;(3)合並。其中,算法的核心部分為對數組進行划分,將小於x的元素放在原數組的左半部分,將大於x的元素放在原數組的右半部分。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <cstdlib>
 4 #include <ctime>
 5 #include <algorithm>
 6 using namespace std;
 7 #define limit 100000
 8 
 9 void quicksort(int a[], int low ,int high)
10 {
11     if(low<high){                //遞歸的終止條件
12         int i = low, j = high;   //使用i,j在對應區間內對數組進行排序;
13         int x = a[low];          //將數組的第一個元素作為哨兵,通過這種方式取出哨兵元素
14 
15         while(i < j){
16           while(i < j && a[j] >= x)
17               j--;               //從右向左尋找第一個比哨兵元素小的元素
18           if(i < j){
19               a[i] = a[j];
20               i++;               //把找到的第一個小於哨兵元素的元素值賦值給第一個元素,並把下界(i)向后移一位
21           }
22 
23           while(i < j && a[i] <= x)
24               i++;                //從左向右尋找第一個比哨兵元素大的元素
25           if(i < j){
26               a[j] = a[i];
27               j--;
28           }                       //把找到的第一個大於哨兵元素的元素值賦值給下標為j的元素,並把上界(j)向前移一位
29         }
30         a[i] = x;                 //把哨兵賦值到下標為i的位置,i前的元素均比哨兵元素小,i后的元素均比哨兵元素大
31 
32         quicksort(a, low ,i-1);   //遞歸進行哨兵前后兩部分元素排序
33         quicksort(a, i+1 ,high);
34     }
35 }
36 int main(void)
37 {
38     ifstream fin;
39     ofstream fout;
40     int x;
41     int i;
42     int a[limit];
43 
44     fin.open("random_number.txt");
45     if(!fin){
46         cerr<<"Can not open file 'random_number.txt' "<<endl;
47         return -1;
48     }
49     time_t first, last;
50 
51 
52     for(i=0; i<limit; i++){
53         fin>>a[i];
54     }
55     fin.close();
56 
57     first = clock();
58 
59     quicksort(a,0,limit-1);
60 
61     last = clock();
62 
63     fout.open("sort_number.txt");
64 
65     if(!fout){
66         cerr<<"Can not open file 'sort_number.txt' "<<endl;
67         return -1;
68     }
69     for(i=0; i<limit; i++){
70         fout<<a[i]<<endl;
71     }
72 
73     fout.close();
74 
75     cout<<"Sort completed (already output to file 'sort_number.txt')!"<<endl;
76     cout<<"Time cost: "<<last-first<<endl;
77 
78     return 0;
79 }

 程序設計思路:

(1)分解:以a[p]為基准元素將a[p:r]划分成3段a[p:q-1],a[q]和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:q-1]和a[q+1:r]的排序是就地進行的,所以在a[p:q-1]和a[q+1:r]都已排好序后不需要執行任何計算,a[p:r]就已排好序。

結果數據格式為time_t格式相減得到的長整型以及輸出到文件的整形數據。

時間復雜性分析:

        對於輸入序列a[p:r],算法的計算時間顯然為O(r-p-1).

        快速排序的運行時間與划分是否對稱有關,其最壞情況發生在划分過程中產生的兩個區域分別包含n-1個元素和1個元素的時候。由於算法的計算時間為O(n),所以如果算法的每一步都出現這種不對稱划分,則其計算時間復雜性T(n)滿足

T(n)= O(1),n≤1

  T(n)= T(n-1)+O(n),n>1

解此遞歸方程可得T(n)=O(n²)

在最好情況下,每次划分所取的基准都恰好為中值,即每次划分都產生兩個大小為n/2的區域,此時,算法的計算時間T(n)滿足

T(n)= O(1),n≤1

   T(n)= 2T(n/2)+O(n),n>1

其解為T(n)=O(nlogn)

        可以證明,快速排序算法在平均情況下的時間復雜性也是O(nlogn)


免責聲明!

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



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