三路快速排序算法

一、三路快速排序算法的基本思想算法

以前的快速排序算法都是將序列分紅<=v和>v或者是<v和>=v的兩個部分,而三路快速排序是函數

將序列分紅三個部分:<v、=v、>v,以下圖所示:佈局

 

 

首先v元素仍是做爲"基準"元素,e表示當前遍歷索引值指向的元素,也就是待考慮的元素,從圖中能夠性能

看出來,整個序列被分紅3個部分,也就是說當咱們遍歷完成以後整個序列就已經被分紅了<v、=v、>v測試

三個部分了,而咱們只須要對<v和>v的兩個部分再次遞歸調用三路排序函數進行排序便可,來看看具體ui

的過程:spa

 

 

首先來看看整個序列的佈局,這裏咱們使用了3個索引值來表示3個不一樣的位置,使用lt索引來表示3d

<v部分和=v部分的分界處(這裏選的是<v部分的最後一個元素),使用i索引表示遍歷的位置,code

使用gt索引來表示=v部分和>v部分的分界處(這裏選的是>v部分的第一個元素)。blog

 

 若是當前i指向的元素=v,那直接就將此元素歸爲=v部分,i++便可

 

 若是當前i指向的元素<v,將此元素與=v部分的第一個元素

                                                               交換位置,也就是swap(arr[i], arr[lt+1]),以後將lt++,

                                                               i++便可,此時<v部分就多了一個元素

 

 若是當前i指向的元素>v,則將此元素與>v部分的第一個元

                                                              素的前一個元素交換位置,也就是swap(arr[i], arr[gt-1]),

                                                              而後gt--,表示>v部分多了一個元素此時i不用動,由於他指

                                                              向的元素是交換過來的,這個元素尚未遍歷到。

 

 當gt與i重合的時候就表示便利完畢了,那麼此時咱們只須要

                                                               將l指向的元素v與lt交換位置便可,以後就以下所示了

 

以後咱們只須要對<v和>v這兩部分再次遞歸進行三路排序,而對於=v的部分就不用在考慮了,由於他們

已經放在了合適的位置了,因此從這裏能夠看出來若是=v部分元素很是多,那麼咱們的三路快速排序算法

效果就會越明顯,這也正是他的優勢所在。

 

二、三路快速排序算法的實現(基於C++)

首先說明,代碼中使用到的索引值變量都是取之於上面的圖示中,這樣便於描述問題

 1 /**************************************三路快速排序算法實現***********************************/
 2 template<typename T>
 3 void __quickSort3Ways (T arr[], int left, int right)
 4 {
 5     if (right - left <= 40) {                  /* 對遞歸到數據量較小時使用插入排序 */
 6         __insertSortMG<T>(arr, left, right);
 7         return;
 8     }
 9 
10     std::swap(arr[left], arr[std::rand() % (right - left + 1) + left]);  // 隨機化找到一個元素做爲"基準"元素 
11     T v = arr[left];
12 
13     int lt = left;       // 將<v的分界線的索引值lt初始化爲第一個元素的位置(也就是<v部分的最後一個元素所在位置)
14     int gt = right + 1;  // 將>v的分界線的索引值gt初始化爲最後一個元素right的後一個元素所在位置(也就是>v部分的第一個元素所在位置)     
15     int i = left + 1;    // 將遍歷序列的索引值i初始化爲 left+1
16     
17     while (i < gt) {     // 循環繼續的條件
18         if (arr[i] < v) {
19             std::swap(arr[i], arr[lt + 1]);  // 若是當前位置元素<v,則將當前位置元素與=v部分的第一個元素交換位置 
20             i++;                             // i++  考慮下一個元素
21             lt++;                            // lt++  表示<v部分多了一個元素
22         }
23         else if (arr[i] > v) {               // 若是當前位置元素>v,則將當前位置元素與>v部分的第一個元素的前一個元素交換位置
24             std::swap(arr[i], arr[gt - 1]);  // 此時i不用動,由於交換過來的元素尚未考慮他的大小
25             gt--;                            // gt--  表示>v部分多了一個元素
26         }
27         else {              //  若是當前位置元素=v   則只須要將i++便可,表示=v部分多了一個元素
28             i++;
29         }
30     }
31 
32     std::swap(arr[left], arr[lt]);   // 上面的遍歷完成以後,將整個序列的第一個元素(也就是"基準"元素)放置到合適的位置 
33                                      // 也就是將它放置在=v部分便可
34     __quickSort3Ways<T>(arr, left, lt - 1); // 對<v部分遞歸調用__quickSort3Ways函數進行三路排序
35     __quickSort3Ways<T>(arr, gt, right);    // 對>v部分遞歸調用__quickSort3Ways函數進行三路排序
36 }
37 
38 template<typename T>
39 void quickSort3Ways (T arr[], int count)
40 {
41     std::srand(std::time(NULL));               /* 種下隨機種子 */
42     __quickSort3Ways<T>(arr, 0, count - 1);    /* 調用__quickSort3Ways函數進行三路快速排序 */
43 }
44 /***********************************************************************************************/

 

三、性能測試

通常排序序列:

 

大量重複元素序列:

 

近乎有序狀態的序列:

相關文章
相關標籤/搜索