[数据结构]快速排序
一、問題描述
內(nèi)部排序是一件具有重大意義的問題,許多項目的實現(xiàn)中都需要用到排序。
我們知道,排序的算法有許多種,每種排序算法的時間復(fù)雜度和空間復(fù)雜度不盡相同。在解決實際問題時,往往需要根據(jù)實際需要選擇排序算法。
上次實驗已經(jīng)討論了希爾排序的實現(xiàn)及其原理,本實驗重點介紹另一種排序算法——快速排序。實驗中將討論快速排序的實現(xiàn)及其原理。
二、數(shù)據(jù)結(jié)構(gòu)——順序結(jié)構(gòu)
本實驗重點在算法實現(xiàn)上,數(shù)據(jù)結(jié)構(gòu)的思想被弱化了。在排序過程中,由于維護(hù)序關(guān)系的需要,要有交換的操作,這就破壞了ADT的物理位置的相鄰反映邏輯的依次的性質(zhì),可以說這里的順序結(jié)構(gòu)只是一個二次結(jié)構(gòu)。因此,本實驗不對此作過多說明。
三、算法的設(shè)計和實現(xiàn)
1、算法描述
快速排序是一種基于比較的排序算法,算法是不穩(wěn)定的。有一種形象的叫法是“挖坑+分治”排序來形容快速排序。以下簡要說明其操作。
以不降序排序為例。選擇序列中一個元素作為基準(zhǔn)元素,本實驗中選擇的是序列區(qū)間的第一個元素。定義兩個指針(這里的指針只是一個意指,不一定用c++語言中真正的指針來實現(xiàn),可以是一個整型數(shù))i和j,初始時分別指向待排序列區(qū)間的首、尾。
每一輪排序時,選擇第一個元素作為基準(zhǔn)元素,相當(dāng)于在序列區(qū)間的第一個位置挖了一個坑,現(xiàn)在要填坑。移動j,直到Elem[j]比基準(zhǔn)元素小,將Elem[j]挖出來填到第一個位置,這時坑就是j這個位置了;移動i,知道Elem[i]比基準(zhǔn)元素大,將Elem[i]挖出來填到j(luò)位置,這時坑就是i這個位置了。重復(fù)上述挖坑、填坑的操作,直到i == j,結(jié)束循環(huán)。此時,將基準(zhǔn)元素填入當(dāng)前的坑里,于是在該基準(zhǔn)元素的左側(cè)的元素都比它小,右側(cè)的都比它大。這時就出現(xiàn)了一個自相似的子結(jié)構(gòu),于是很自然地選擇遞歸,將當(dāng)前的待排序序列區(qū)間以基準(zhǔn)元素的位置一分為二,分別重復(fù)上述過程。遞歸的邊界是當(dāng)前區(qū)間只有一個元素,平凡有序。
所謂“挖坑”上面已經(jīng)提到了,所謂“分治”就是指的區(qū)間一分為二的遞歸過程。
2、算法復(fù)雜度分析
快速排序的時間主要耗費在劃分操作上,設(shè)當(dāng)前待排序區(qū)間長度為k,則共需要k-1次關(guān)鍵字的比較。
最壞情況是每次劃分選取的基準(zhǔn)元素都是當(dāng)前區(qū)間的最小(或者最大)元素,那么劃分的結(jié)果將是左邊的子區(qū)間(或者右邊的子區(qū)間)為空,而右邊的子區(qū)間(或者左邊的子區(qū)間)長度為k-1,僅比之前少一個元素。此時的時間復(fù)雜度為O(n^2)。
最好情況是每次劃分選取的基準(zhǔn)元素都正好是當(dāng)前區(qū)間的中位數(shù),劃分的結(jié)果是左、右子區(qū)間元素個數(shù)大致相等,總的復(fù)雜度為O(n lgn)。
盡管快速排序的最壞情況復(fù)雜度逼近平方級別,但就平均性能而言,它是基于關(guān)鍵字比較的內(nèi)部排序算法中速度最快的(這個網(wǎng)上有許多算法的時間測試,這里不再贅述),它的平均時間復(fù)雜度為O(n lgn)。
3、例子
(1)第一輪
| 基準(zhǔn)元素下標(biāo) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 72 | 72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
| ? | 48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
| ? | 48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 88 | 85 |
| ? | 48 | 6 | 57 | 42 | 60 | 42 | 83 | 73 | 88 | 85 |
| ? | 48 | 6 | 57 | 42 | 60 | 72 | 83 | 73 | 88 | 85 |
(2)第二輪
a)區(qū)間[1,5]
| 基準(zhǔn)元素下標(biāo) | 1 | 2 | 3 | 4 | 5 |
| 48 | 48 | 6 | 57 | 42 | 60 |
| ? | 42 | 6 | 57 | 42 | 60 |
| ? | 42 | 6 | 57 | 57 | 60 |
| ? | 42 | 6 | 48 | 57 | 60 |
b)區(qū)間[7,10]
| 基準(zhǔn)元素下標(biāo) | 7 | 8 | 9 | 10 |
| 83 | 83 | 73 | 88 | 85 |
| ? | 73 | 73 | 88 | 85 |
| ? | 73 | 83 | 88 | 85 |
c)總的序列
| 42 | 6 | 48 | 57 | 60 | 72 | 73 | 83 | 88 | 85 |
(3)第三輪
a)區(qū)間[1,2]
| 基準(zhǔn)元素下標(biāo) | 1 | 2 |
| 42 | 42 | 6 |
| ? | 6 | 6 |
| ? | 6 | 42 |
b)區(qū)間[4,5]
| 基準(zhǔn)元素下標(biāo) | 4 | 5 |
| 57 | 57 | 60 |
| ? | 57 | 60 |
c)區(qū)間[7,7],直接返回
d)區(qū)間[9,10]
| 基準(zhǔn)元素下標(biāo) | 9 | 10 |
| 88 | 88 | 85 |
| ? | 85 | 85 |
| ? | 85 | 88 |
e)總的序列
| 6 | 42 | 48 | 57 | 60 | 72 | 73 | 83 | 85 | 88 |
排序完成
四、預(yù)期結(jié)果和實驗中的問題
1、預(yù)期結(jié)果
程序能夠正確地將一個序列按照不遞減的順序排序。下圖為一個例子。
2、實驗中的問題及思考
快速排序還有一些改進(jìn)的版本,當(dāng)然比較常見的是在選擇基準(zhǔn)元素的時候采用隨機(jī)選擇的方式。據(jù)研究表明,選擇黃金分割點處的數(shù)作為基準(zhǔn)元素的期望速度最快,這個我還沒有仔細(xì)學(xué)習(xí)過。
附:c++源代碼:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 #define MaxN 120 7 8 int gap[200]; //步長 2^k+1 第一項改為1 9 int n; 10 11 template <class T> class My_list 12 { 13 private: 14 T Elem[MaxN]; //待排序的元素 15 int Len; //元素個數(shù) 16 public: 17 void Init() 18 { 19 memset(Elem, 0, sizeof(Elem)); 20 Len = 0; 21 } 22 void Insert_back(T x) 23 { 24 Elem[++Len] = x; 25 } 26 void Print() 27 { 28 int i; 29 for(i = 1; i < Len; i++) 30 printf("%d ", Elem[i]); 31 printf("%d\n", Elem[i]); 32 } 33 int GetLen() 34 { 35 return Len; 36 } 37 void QuickSort(int st, int ed) 38 { 39 if(st < ed) 40 { 41 int i = st, j = ed, x = Elem[st]; 42 while(i < j) 43 { 44 while(i < j && Elem[j] > x) //找右側(cè)比x大的元素 45 j--; 46 if(i < j) 47 Elem[i++] = Elem[j]; 48 while(i < j && Elem[i] < x) //找左側(cè)比x小的元素 49 i++; 50 if(i < j) 51 Elem[j--] = Elem[i]; 52 } 53 Elem[i] = x; 54 QuickSort(st, i - 1); //分治左側(cè)區(qū)間 55 QuickSort(i + 1, ed); //分治右側(cè)區(qū)間 56 } //if 57 } 58 }; 59 60 void Read(My_list <int> &L) 61 { 62 int i, x; 63 L.Init(); 64 printf("請輸入需要排序的數(shù)的個數(shù)。\n"); 65 scanf("%d", &n); 66 printf("請輸入需要排序的數(shù)列。\n"); 67 for(i = 1; i <= n; i++) 68 { 69 scanf("%d", &x); 70 L.Insert_back(x); //把x插入到最后 71 } 72 } 73 74 int main() 75 { 76 int GapNum; 77 My_list <int> L; 78 Read(L); 79 L.QuickSort(1, n); 80 printf("升序排序后的數(shù)列:\n"); 81 L.Print(); 82 return 0; 83 } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/CQBZOIer-zyy/p/5185409.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的[数据结构]快速排序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机的前世
- 下一篇: [LintCode] strStr [K