快速排序是將分治法運用到排序問題中的乙個典型例子,快速排序的基本思想是:通過
乙個樞軸(pivot)元素將 n 個元素的序列分為左、右兩個子串行 ll 和 lr,其中子串行 ll中的元素均比樞軸元素小,而子串行 lr 中的元素均比樞軸元素大,然後對左、右子串行分別進行快速排序,在將左、右子串行排好序後,則整個序列有序,而對左右子串行的排序過程直到子串行中只包含乙個元素時結束,此時左、右子串行由於只包含乙個元素則自然有序。用分治法的三個步驟來描述快速排序的過程如下:
劃分步驟:通過樞軸元素 x 將序列一分為二, 且左子串行的元素均小於 x,右子
序列的元素均大於 x;
治理步驟:遞迴的對左、右子串行排序;
組合步驟:無
從上面快速排序演算法的描述中我們看到,快速排序演算法的實現依賴於按照樞軸元素 x對待排序序列進行劃分的過程。對待排序序列進行劃分的做法是:使用兩個指標 low 和 high 分別指向待劃分序列 r 的範圍,取 low 所指元素為樞軸,即 pivot = r[low]。劃分首先從 high 所指位置的元素起向前逐一搜尋到第乙個比 pivot 小的元素,並將其設定到 low 所指的位置;然後從 low 所指位置的元素起向後逐一搜尋到第乙個比 pivot 大的元素,並將其設定到 high 所指的位置;不斷重複上述兩步直到 low = high 為止,最後將 pivot 設定到 low 與 high 共同指向的位置。
package com.algorithm.sorting;
/** * 快速排序
* */
public
class
quicksort
system.out.println("");
int i, j, temp;
// 定義變數temp,作為標準資料元素
if (low < high)
while (i < j && a[i] < temp)
i++;
// 陣列的左端向右端掃瞄
if (i < j)
}a[i] = temp;
// system.out.println(i);
quicksort(a, low, i - 1);
// 對左端子集合進行遞迴
quicksort(a, i + 1, high);
// 對右端子集合進行遞迴}}
public
static
void
main(string args) ;
quicksort(array, 0, 5);
system.out.print("最終排序結果:");
for (int i = 0; i < array.length; i++)
}}
首先看排序的過程:
pivot樞軸元素,也可以理解為陣列中間大小元素
要排序的陣列:99
3020 -1
10053
//原始陣列
pivot=99
要排序的陣列:53
3020 -1
99100
//第一次交換後陣列
pivot=53
要排序的陣列:-1
3020
5399
100//第二次交換後陣列
pivot=-1
要排序的陣列:-1
3020
5399
100//第三次交換後陣列
要排序的陣列:-1
3020
5399
100
pivot=30
要排序的陣列:-1
2030
5399
100//第四次交換後陣列
要排序的陣列:-1
2030
5399
100
要排序的陣列:-1
2030
5399
100
要排序的陣列:-1
2030
5399
100
最終排序結果:-1
2030
5399
100
假設要排序的陣列是a[1]……a[n],首先任意選取乙個資料(通常選用第乙個資料)作為關鍵資料,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一躺快速排序。一躺快速排序的演算法是:
1)、設定兩個變數i、j,排序開始的時候i:=1,j:=n;
2)以第乙個陣列元素作為關鍵資料,賦值給x,即x:=a[1];
3)、從j開始向前搜尋,即由後開始向前搜尋(j:=j-1),找到第乙個小於x的值,兩者交換;
4)、從i開始向後搜尋,即由前開始向後搜尋(i:=i+1),找到第乙個大於x的值,兩者交換;
5)、重複第3、4步,直到i=j;
例如:待排序的陣列a的值分別是:(初始關鍵資料x:=49)
49 38 65 97 76 13 27
進行第一次交換後:
27 38 65 97 76 13 49
進行第二次交換後:
27 38 49 97 76 13 65
進行第三次交換後:
27 38 13 97 76 49 65
進行第四次交換後:
27 38 13 49 76 97 65
此時再執行第三不的時候就發現i=j,從而結束一躺快速排序,那麼經過一躺快速排序之後的結果是:
27 38 13 49 76 97 65,即所以大於49的數全部在49的後面,所以小於49的數全部在49的前面。
時間效率:快速排序演算法的執行時間依賴於劃分是否平衡,即根據樞軸元素 pivot 將序列劃分為兩個子串行中的元素個數,而劃分是否平衡又依賴於所使用的樞軸元素。下面我們在不同的情況下來分析快速排序的漸進時間複雜度。
快速排序的最壞情況是每次進行劃分時,在所得到的兩個子串行中有乙個子串行為空。
此時,演算法的時間複雜度t(n) = t p (n) + t(n-1),其中t p (n)是對具有n個元素的序列進行劃分所需的時間,由以上劃分演算法的過程可以得到t p (n) = θ(n)。由此,t(n) =θ(n) + t(n-1) =θ(
n2) θ(n
2)
。 在快速排序過程中,如果總是選擇r[low]作為樞軸元素,則在待排序序列本身已經有序或逆向有序時,快速排序的時間複雜度為ο(n 2 ),而在有序時插入排序的時間複雜度為ο(n)。
快速排序的最好情況是在每次劃分時,都將序列一分為二,正好在序列中間將序列分成長度相等的兩個子串行。此時,演算法的時間複雜度t(n) = t p (n) + 2t(n/2),由於t p (n) = θ(n),所以t(n) = 2t(n/2) +θ(n),由master method知道t(n) = θ(n log n)。
在平均情況下,快速排序的時間複雜度 t(n) = kn ㏑ n,其中 k 為某個常數,經驗證明,在所有同數量級的排序方法中,快速排序的常數因子 k 是最小的。因此就平均時間而言,快速排序被認為是目前最好的一種內部排序方法。
快速排序的平均效能最好,但是,若待排序序列初始時已按關鍵字有序或基本有序,則快速排序蛻化為起泡排序,其時間複雜度為o(
n2) ο(n
2)
。為改進之,可以採取隨機選擇樞軸元素pivot的方法,具體做法是,在待劃分的序列中隨機選擇乙個元素然後與r[low]交換,再將r[low]作為樞軸元素,作如此改進之後將極大改進快速排序在序列有序或基本有序時的效能,在待排序元素個數n較大時,其執行過程中出現最壞情況的可能性可以認為不存在。
空間效率:雖然從時間上看快速排序的效率優於前述演算法,然而從空間上看,在前面討
論的演算法中都只需要乙個輔助空間,而快速排序需要乙個堆疊來實現遞迴。若每次劃分都將
序列均勻分割為長度相近的兩個子串行,則堆疊的最大深度為 log n,但是,在最壞的情況
下,堆疊的最大深度為 n。
Java排序演算法之快速排序
首先在陣列中選擇乙個基準點 該基準點的選取可能影響快速排序的效率,後面講解選取的方法 然後分別從陣列的兩端掃瞄陣列,設兩個指示標誌 lo指向起始位置,hi指向末尾 首先從後半部分開始,如果發現有元素比該基準點的值小,就交換lo和hi位置的值,然後從前半部分開始掃秒,發現有元素大於基準點的值,就交換l...
Java排序演算法之快速排序
基本思想 在資料序列中選擇乙個值作為比較的基準值,每趟從資料序列的兩端開始交替進行,將小於基準值的元素交換到序列前端,將大於基準值的元素交換到序列後端,介於兩者之間的位置則成為基準值的最終位置,直到子串行長度為1,完成排序 以序列,進行快速排序,以下是一趟快速排序過程示意圖 private stat...
Java排序演算法 快速排序
一.思想 對氣泡排序演算法的一種改進。通過一趟排序將排序的資料分割成兩個部分,其中一部分的所有資料都比另一部分的所有資料都要小,然後再按此方法對這兩部分分別再進行快速排序,依次類推。實現為 開始時先設兩個變數i start,j end 以第乙個元素作為中間點,pivot num i 以j 的形式從後...