排序算法是算法學習的第一步,想當初我學的第一個算法就是選擇排序,不過當時很長一段時間我都不清楚我到底用的是選擇還是冒泡還是插入。只記得兩個for一個if排序就完成了。
再後來更系統地接觸算法,才發現那纔是排序算法隊伍中小小而基本的一員。
買的《算法導論》一直沒有認真地看一看,下來要找實習找工作,爲了做準備,也是爲了複習一下算法,便扒出來好好學一學,並做一些記錄,免得我金魚般的記憶使我看了和沒看一樣。
快速排序
快速排序用到了分治思想,同樣的還有歸併排序。乍看起來快速排序和歸併排序非常相似,都是將問題變小,先排序子串,最後合併。不同的是快速排序在劃分子問題的時候經過多一步處理,將劃分的兩組數據劃分爲一大一小,這樣在最後合併的時候就不必像歸併排序那樣再進行比較。但也正因爲如此,劃分的不定性使得快速排序的時間複雜度並不穩定。
快速排序的期望複雜度是O(nlogn),但最壞情況下可能就會變成O(n^2),最壞情況就是每次將一組數據劃分爲兩組的時候,分界線都選在了邊界上,使得劃分了和沒劃分一樣,最後就變成了普通的選擇排序了。
快速排序分爲三步分治過程,劃分,解決,合併。
分解是將輸入數組A[l..r]劃分成兩個子數組的過程。選擇一個p,使得a被劃分成三部分,分別是a[l..p-1],a[p]和a[p+1..r]。並且使得a[l..p-1]中的元素都小於等於(或大於等於)a[p],同時a[p]小於等於(或大於等於)a[p+1..r]中的所有元素。
解決是調用遞歸程序,解決分解中劃分生成的兩個子序列。
合併是遞歸到最深層,已經不能再劃分成更小的子序列了,便開始合併。因爲在分解的時候已經比較過大小,每一個父序列分解而來的兩個子序列不僅是有序的,而且合併成一個序列之後還是有序的。因爲快排可以在輸入數組上進行操作,所以合併這一步不需要編寫代碼。
《算法導論》上稱這樣的排序爲原址排序,即在原數組上操作就可以完成排序,不需要臨時數組。
書上的代碼非常簡潔巧妙,我就不把書上的僞代碼照抄上來了,這裏給出Java的實現代碼以供參考:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//快速排序</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">QuickSort</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> left, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (left < right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> p = partition(a, left, right); QuickSort(a, left, p - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); QuickSort(a, p + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, right); } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//快速排序數組劃分</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">partition</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> left, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x = a[right]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> p = left - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = left; i < right; i++) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (a[i] <= x) { p++; swap(a, p, i); } } swap(a, p+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, right); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> p+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>
其中的swap函數如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//交換數組a中的a[i]和a[j]</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">swap</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> j) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> temp = a[i]; a[i] = a[j]; a[j] = temp; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
QuickSort(int[] a,int left,int right)
函數沒什麼好說的,設置遞歸邊界,接下來遞歸處理左序列,再處理右序列。
下來的partition(int[] a, int left, int right)
就比較有意思了。
int x = a[right];
這行代碼選中一個主元,這裏我們每次選擇的都是當前序列中最右邊那個。int
p = left - 1;
這行代碼保存了一個變量p,用來記錄比主元小的所有元素中,在序列中存放的位置最靠右的那個。接下來是個循環,從當前序列的第一個循環到倒數第二個(right-1)元素,來進行和主元比較。因爲最後一個已經是主元了,所以就沒有必要循環到right了。循環裏面先是一個比較if
(a[i] <= x)
。這裏寫的是小於等於,更改這個就可以改變序列式由小到大還是由大到小排列。這裏則是由小到大排列。如果進入了if語句,則說明a[i](當前元素)比主元小,還記得之前的變量p嗎,保存着比主元小的元素最右邊的位置,這裏先p++,接着把a[i]和a[p]交換,就是說把a[p]右邊的元素和當前元素換位置。a[p]右邊的元素是什麼呢?可能就是當前元素,也可能是比主元大的元素。這樣,就完成了比主元小的元素的處理。
可是如果a[i]>x呢,則不進入if執行這兩行代碼,也就是不動那個比主元大的元素。
這樣直到循環結束,整個序列就變成了三部分,從a[left..p]是比主元小的元素,a[p+1..right-1]是比主元大的元素,a[right]則是主元。而我們劃分的目的是將主元放在這兩個序列的中間,則再執行一行語句swap(a,
p+1, right);
,將主元和比它大序列的第一個元素互換位置,就大功告成了。
書上的圖解非常的清晰:(標號是根據上面代碼所標,和書上不太一樣,但意思是一樣的)
這張圖描述了一次劃分。淺藍色部分是不大於主元的部分,深藍色部分是大於主元的部分。沒有顏色的是還未處理的元素,最後的元素則是主元。
快速排序的主要內容差不多就這些了,書上接下來證明了快速排序的正確性,以及計算了其時間複雜度。之後討論了劃分的不平衡性所導致的性能退化。對一個排好序的序列使用上述快排,時間複雜度爲O(n^2),而插入排序則僅爲O(n)。因此便有了隨機化快速排序的出現。
快速排序的隨機化版本
上面版本的快排在選取主元的時候,每次都選取最右邊的元素。當序列爲有序時,會發現劃分出來的兩個子序列一個裏面沒有元素,而另一個則只比原來少一個元素。爲了避免這種情況,引入一個隨機化量來破壞這種有序狀態。
在隨機化的快排裏面,選取a[left..right]中的隨機一個元素作爲主元,然後再進行劃分,就可以得到一個平衡的劃分。
實現起來其實只需要對上面的代碼做小小的修改就可以了。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//快速排序的隨機化版本,除了調用劃分函數不同,和之前快排的代碼結構一模一樣</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">RandomQuickSort</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> left, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (left < right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> p = randomPartition(a, left, right); RandomQuickSort(a, left, p - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); RandomQuickSort(a, p + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, right); } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//隨機化劃分</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">randomPartition</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> left, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> right) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> r = random.nextInt(right - left) + left; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//生成一個隨機數,即是主元所在位置</span> swap(a, right, r); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//將主元與序列最右邊元素互換位置,這樣就變成了之前快排的形式。</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> partition(a, left, right); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//直接調用之前的代碼</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
這裏的random是一個已經初始化過的Random的靜態對象。
隨機化快排就這樣就ok了。
性能分析
隨機序列
爲了比較普通快排和隨機化快排的性能,我做了一些測試。因爲沒有太多的經驗,測試結果僅供參考。:)
數組生成代碼
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">Random random = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Random(Calendar.getInstance().getTimeInMillis()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] a = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000000</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] b = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000000</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < a.length; i++) { a[i] = random.nextInt(Integer.MAX_VALUE); b[i] = a[i]; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
測試代碼:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//隨機化快排</span> startTime = System.currentTimeMillis(); Sort.RandomQuickSort(a, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, a.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); endTime = System.currentTimeMillis(); o(String.format(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"RandomQuickSort Finished. Cost %dms\n"</span>, endTime - startTime));<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//o是一個輸出函數,把系統的System.out.print()簡單封裝了一下,打起來短一些……</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//快排</span> startTime = System.currentTimeMillis(); Sort.QuickSort(b, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, b.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); endTime = System.currentTimeMillis(); o(String.format(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"QuickSort Finished. Cost %dms\n"</span>, endTime - startTime));</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
結果:
RandomQuickSort Finished. Cost 1417ms
QuickSort Finished. Cost 1367ms
多次實驗結果:
10w:
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
普通快排 | 13ms | 15ms | 15ms | 14.333ms |
隨機化版本快排 | 25ms | 25ms | 27ms | 25.667ms |
100w:
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
普通快排 | 101ms | 103ms | 96ms | 100ms |
隨機化版本快排 | 119ms | 101ms | 105ms | 108.333ms |
1000w:
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
普通快排 | 1397ms | 1379ms | 1338ms | 1371.333ms |
隨機化版本快排 | 1241ms | 1187ms | 1258ms | 1228.667ms |
隨機化快排因爲要生成隨機數,所以有一些性能損失,所以數據規模較小,數據分佈均勻時普通快排還是比隨機化快排要快些的,不過隨着數據規模的上升,隨機化快排的性能優勢就展現出來了。
有序序列
下來纔是展示快排才華的時候,假設當輸入數組已經是排好序的,這兩個算法的性能差距又有多少?
之前的數組生成代碼不變,只是在調用兩個算法之前,先調用一下快排將數組排序,然後將兩個有序的數組作爲參數傳進去。
10w:
10w的普通快排……已經棧溢出了。
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
普通快排 | 溢出 | 溢出 | 溢出 | 溢出 |
隨機化版本快排 | 15ms | 7ms | 6ms | 9.333ms |
1w:
試一試1w的
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
普通快排 | 98ms | 94ms | 92ms | 94.667ms |
隨機化版本快排 | 2ms | 1ms | 0ms | 1ms |
1000w:
看下1000w下隨機化快排是否有影響
算法 | 第1次耗時 | 第2次耗時 | 第3次耗時 | 平均耗時 |
---|---|---|---|---|
隨機化版本快排 | 696ms | 733ms | 689ms | 706ms |
這篇筆記就到這兒了,希望能通過講解一遍加深記憶,也希望能給別人帶來哪怕一點點幫助。
參考書籍:機械工業出版社 第三版《算法導論》部分內容引自原書