當前位置:首頁 » 操作系統 » 快速排序演算法程序

快速排序演算法程序

發布時間: 2023-01-06 06:10:50

① 快速排序演算法

C語言程序: /* 快 速 排 序 */ #include "stdio.h" void QuickSort(int e[], int first, int end) { int i=first,j=end,temp=e[first];,xgXBjE

② 快速排序法

快速排序(Quicksort)是對冒泡排序的一種改進。[1]

快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。[1]

中文名
快速排序演算法
外文名
quick sort
別名
快速排序
提出者
C. A. R. Hoare
提出時間
1960年
快速
導航
排序步驟

程序調用舉例

示例代碼

性能分析
排序流程
快速排序演算法通過多次比較和交換來實現排序,其排序流程如下:[2]
(1)首先設定一個分界值,通過該分界值將數組分成左右兩部分。[2]
(2)將大於或等於分界值的數據集中到數組右邊,小於分界值的數據集中到數組的左邊。此時,左邊部分中各元素都小於或等於分界值,而右邊部分中各元素都大於或等於分界值。[2]
(3)然後,左邊和右邊的數據可以獨立排序。對於左側的數組數據,又可以取一個分界值,將該部分數據分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側的數組數據也可以做類似處理。[2]
(4)重復上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側部分排好序後,再遞歸排好右側部分的順序。當左、右兩個部分各數據排序完成後,整個數組的排序也就完成了。[2]
排序步驟
原理
設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(通常選

快排圖
用數組的第一個數)作為關鍵數據,然後將所有比它小的數都放到它左邊,所有比它大的數都放到它右邊,這個過程稱為一趟快速排序。值得注意的是,快速排序不是一種穩定的排序演算法,也就是說,多個相同的值的相對位置也許會在演算法結束時產生變動。[1]
一趟快速排序的演算法是:[1]
1)設置兩個變數i、j,排序開始的時候:i=0,j=N-1;[1]
2)以第一個數組元素作為關鍵數據,賦值給key,即key=A[0];[1]
3)從j開始向前搜索,即由後開始向前搜索(j--),找到第一個小於key的值A[j],將A[j]和A[i]的值交換;[1]
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]的值交換;[1]
5)重復第3、4步,直到i==j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)。[1]
排序演示
假設一開始序列{xi}是:5,3,7,6,4,1,0,2,9,10,8。
此時,ref=5,i=1,j=11,從後往前找,第一個比5小的數是x8=2,因此序列為:2,3,7,6,4,1,0,5,9,10,8。
此時i=1,j=8,從前往後找,第一個比5大的數是x3=7,因此序列為:2,3,5,6,4,1,0,7,9,10,8。
此時,i=3,j=8,從第8位往前找,第一個比5小的數是x7=0,因此:2,3,0,6,4,1,5,7,9,10,8。

③ 快速排序演算法的示例代碼

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespacetest{classQuickSort{staticvoidMain(string[]args){int[]array={49,38,65,97,76,13,27};sort(array,0,array.Length-1);Console.ReadLine();}/**一次排序單元,完成此方法,key左邊都比key小,key右邊都比key大。**@paramarray排序數組**@paramlow排序起始位置**@paramhigh排序結束位置**@return單元排序後的數組*/privatestaticintsortUnit(int[]array,intlow,inthigh){intkey=array[low];while(low<high){/*從後向前搜索比key小的值*/while(array[high]>=key&&high>low)--high;/*比key小的放左邊*/array[low]=array[high];/*從前向後搜索比key大的值,比key大的放右邊*/while(array[low]<=key&&high>low)++low;/*比key大的放右邊*/array[high]=array[low];}/*左邊都比key小,右邊都比key大。//將key放在游標當前位置。//此時low等於high*/array[low]=key;foreach(intiinarray){Console.Write({0} ,i);}Console.WriteLine();returnhigh;}/**快速排序*@paramarry*@return*/publicstaticvoidsort(int[]array,intlow,inthigh){if(low>=high)return;/*完成一次單元排序*/intindex=sortUnit(array,low,high);/*對左邊單元進行排序*/sort(array,low,index-1);/*對右邊單元進行排序*/sort(array,index+1,high);}}}運行結果:27 38 13 49 76 97 65
13 27 38 49 76 97 6513 27 38 49 65 76 97
快速排序就是遞歸調用此過程——在以49為中點分割這個數據序列,分別對前面一部分和後面一部分進行類似的快速排序,從而完成全部數據序列的快速排序,最後把此數據序列變成一個有序的序列,根據這種思想對於上述數組A的快速排序的全過程如圖6所示:
初始狀態 {49 38 65 97 76 13 27} 進行一次快速排序之後劃分為 {27 38 13} 49 {76 97 65} 分別對前後兩部分進行快速排序{27 38 13} 經第三步和第四步交換後變成 {13 27 38} 完成排序。{76 97 65} 經第三步和第四步交換後變成 {65 76 97} 完成排序。圖示 快速排序的最壞情況基於每次劃分對主元的選擇。基本的快速排序選取第一個元素作為主元。這樣在數組已經有序的情況下,每次劃分將得到最壞的結果。一種比較常見的優化方法是隨機化演算法,即隨機選取一個元素作為主元。這種情況下雖然最壞情況仍然是O(n^2),但最壞情況不再依賴於輸入數據,而是由於隨機函數取值不佳。實際上,隨機化快速排序得到理論最壞情況的可能性僅為1/(2^n)。所以隨機化快速排序可以對於絕大多數輸入數據達到O(nlogn)的期望時間復雜度。一位前輩做出了一個精闢的總結:「隨機化快速排序可以滿足一個人一輩子的人品需求。」
隨機化快速排序的唯一缺點在於,一旦輸入數據中有很多的相同數據,隨機化的效果將直接減弱。對於極限情況,即對於n個相同的數排序,隨機化快速排序的時間復雜度將毫無疑問的降低到O(n^2)。解決方法是用一種方法進行掃描,使沒有交換的情況下主元保留在原位置。 QUICKSORT(A,p,r)
1if p<r
2then q ←PARTITION(A,p,r)
3QUICKSORT(A,p,q-1)
4QUICKSORT(A,q+1,r)
為排序一個完整的數組A,最初的調用是QUICKSORT(A,1,length[A])。
快速排序演算法的關鍵是PARTITION過程,它對子數組A[p..r]進行就地重排:
PARTITION(A,p,r)
1x←A[r]
2i←p-1
3for j←p to r-1
4do if A[j]≤x
5then i←i+1
6exchange A[i]←→A[j]
7exchange A[i+1]←→A[r]
8return i+1 對PARTITION和QUICKSORT所作的改動比較小。在新的劃分過程中,我們在真正進行劃分之前實現交換:
(其中PARTITION過程同快速排序偽代碼(非隨機))
RANDOMIZED-PARTITION(A,p,r)
1i← RANDOM(p,r)
2exchange A[r]←→A[i]
3return PARTITION(A,p,r)
新的快速排序過程不再調用PARTITION,而是調用RANDOMIZED-PARTITION。
RANDOMIZED-QUICKSORT(A,p,r)
1if p<r
2then q← RANDOMIZED-PARTITION(A,p,r)
3RANDOMIZED-QUICKSORT(A,p,q-1)
4RANDOMIZED-QUICKSORT(A,q+1,r) 這里為方便起見,我們假設演算法Quick_Sort的范圍閾值為1(即一直將線性表分解到只剩一個元素),這對該演算法復雜性的分析沒有本質的影響。
我們先分析函數partition的性能,該函數對於確定的輸入復雜性是確定的。觀察該函數,我們發現,對於有n個元素的確定輸入L[p..r],該函數運行時間顯然為θ(n)。
最壞情況
無論適用哪一種方法來選擇pivot,由於我們不知道各個元素間的相對大小關系(若知道就已經排好序了),所以我們無法確定pivot的選擇對劃分造成的影響。因此對各種pivot選擇法而言,最壞情況和最好情況都是相同的。
我們從直覺上可以判斷出最壞情況發生在每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的時候(設輸入的表有n個元素)。下面我們暫時認為該猜測正確,在後文我們再詳細證明該猜測。
對於有n個元素的表L[p..r],由於函數Partition的計算時間為θ(n),所以快速排序在序壞情況下的復雜性有遞歸式如下:
T(1)=θ(1),T(n)=T(n-1)+T(1)+θ(n) (1)
用迭代法可以解出上式的解為T(n)=θ(n2)。
這個最壞情況運行時間與插入排序是一樣的。
下面我們來證明這種每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的情況就是最壞情況。
設T(n)是過程Quick_Sort作用於規模為n的輸入上的最壞情況的時間,則
T(n)=max(T(q)+T(n-q))+θ(n),其中1≤q≤n-1 (2)
我們假設對於任何k<n,總有T(k)≤ck,其中c為常數;顯然當k=1時是成立的。
將歸納假設代入(2),得到:
T(n)≤max(cq2+c(n-q)2)+θ(n)=c*max(q2+(n-q)2)+θ(n)
因為在[1,n-1]上q2+(n-q)2關於q遞減,所以當q=1時q2+(n-q)2有最大值n2-2(n-1)。於是有:
T(n)≤cn2-2c(n-1)+θ(n)≤cn2
只要c足夠大,上面的第二個小於等於號就可以成立。於是對於所有的n都有T(n)≤cn。
這樣,排序演算法的最壞情況運行時間為θ(n2),且最壞情況發生在每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的時候。
時間復雜度為o(n2)。
最好情況
如果每次劃分過程產生的區間大小都為n/2,則快速排序法運行就快得多了。這時有:
T(n)=2T(n/2)+θ(n),T(1)=θ(1) (3)
解得:T(n)=θ(nlogn)
快速排序法最佳情況下執行過程的遞歸樹如下圖所示,圖中lgn表示以10為底的對數,而本文中用logn表示以2為底的對數.
由於快速排序法也是基於比較的排序法,其運行時間為Ω(nlogn),所以如果每次劃分過程產生的區間大小都為n/2,則運行時間θ(nlogn)就是最好情況運行時間。
但是,是否一定要每次平均劃分才能達到最好情況呢?要理解這一點就必須理解對稱性是如何在描述運行時間的遞歸式中反映的。我們假設每次劃分過程都產生9:1的劃分,乍一看該劃分很不對稱。我們可以得到遞歸式:
T(n)=T(n/10)+T(9n/10)+θ(n),T(1)=θ(1) (4)
請注意樹的每一層都有代價n,直到在深度log10n=θ(logn)處達到邊界條件,以後各層代價至多為n。遞歸於深度log10/9n=θ(logn)處結束。這樣,快速排序的總時間代價為T(n)=θ(nlogn),從漸進意義上看就和劃分是在中間進行的一樣。事實上,即使是99:1的劃分時間代價也為θ(nlogn)。其原因在於,任何一種按常數比例進行劃分所產生的遞歸樹的深度都為θ(nlogn),其中每一層的代價為O(n),因而不管常數比例是什麼,總的運行時間都為θ(nlogn),只不過其中隱含的常數因子有所不同。(關於演算法復雜性的漸進階,請參閱演算法的復雜性)
平均情況
快速排序的平均運行時間為θ(nlogn)。
我們對平均情況下的性能作直覺上的分析。
要想對快速排序的平均情況有個較為清楚的概念,我們就要對遇到的各種輸入作個假設。通常都假設輸入數據的所有排列都是等可能的。後文中我們要討論這個假設。
當我們對一個隨機的輸入數組應用快速排序時,要想在每一層上都有同樣的劃分是不太可能的。我們所能期望的是某些劃分較對稱,另一些則很不對稱。事實上,我們可以證明,如果選擇L[p..r]的第一個元素作為支點元素,Partition所產生的劃分80%以上都比9:1更對稱,而另20%則比9:1差,這里證明從略。
平均情況下,Partition產生的劃分中既有「好的」,又有「差的」。這時,與Partition執行過程對應的遞歸樹中,好、差劃分是隨機地分布在樹的各層上的。為與我們的直覺相一致,假設好、差劃分交替出現在樹的各層上,且好的劃分是最佳情況劃分,而差的劃分是最壞情況下的劃分。在根節點處,劃分的代價為n,劃分出來的兩個子表的大小為n-1和1,即最壞情況。在根的下一層,大小為n-1的子表按最佳情況劃分成大小各為(n-1)/2的兩個子表。這兒我們假設含1個元素的子表的邊界條件代價為1。
在一個差的劃分後接一個好的劃分後,產生出三個子表,大小各為1,(n-1)/2和(n-1)/2,代價共為2n-1=θ(n)。一層劃分就產生出大小為(n-1)/2+1和(n-1)/2的兩個子表,代價為n=θ(n)。這種劃分差不多是完全對稱的,比9:1的劃分要好。從直覺上看,差的劃分的代價θ(n)可被吸收到好的劃分的代價θ(n)中去,結果是一個好的劃分。這樣,當好、差劃分交替分布劃分都是好的一樣:仍是θ(nlogn),但θ記號中隱含的常數因子要略大一些。關於平均情況的嚴格分析將在後文給出。
在前文從直覺上探討快速排序的平均性態過程中,我們已假定輸入數據的所有排列都是等可能的。如果輸入的分布滿足這個假設時,快速排序是對足夠大的輸入的理想選擇。但在實際應用中,這個假設就不會總是成立。
解決的方法是,利用隨機化策略,能夠克服分布的等可能性假設所帶來的問題。
一種隨機化策略是:與對輸入的分布作「假設」不同的是對輸入的分布作「規定」。具體地說,在排序輸入的線性表前,對其元素加以隨機排列,以強制的方法使每種排列滿足等可能性。事實上,我們可以找到一個能在O(n)時間內對含n個元素的數組加以隨機排列的演算法。這種修改不改變演算法的最壞情況運行時間,但它卻使得運行時間能夠獨立於輸入數據已排序的情況。
另一種隨機化策略是:利用前文介紹的選擇支點元素pivot的第四種方法,即隨機地在L[p..r]中選擇一個元素作為支點元素pivot。實際應用中通常採用這種方法。
快速排序的隨機化版本有一個和其他隨機化演算法一樣的有趣性質:沒有一個特別的輸入會導致最壞情況性態。這種演算法的最壞情況性態是由隨機數產生器決定的。你即使有意給出一個壞的輸入也沒用,因為隨機化排列會使得輸入數據的次序對演算法不產生影響。只有在隨機數產生器給出了一個很不巧的排列時,隨機化演算法的最壞情況性態才會出現。事實上可以證明幾乎所有的排列都可使快速排序接近平均情況性態,只有非常少的幾個排列才會導致演算法的近最壞情況性態。
一般來說,當一個演算法可按多條路子做下去,但又很難決定哪一條保證是好的選擇時,隨機化策略是很有用的。如果大部分選擇都是好的,則隨機地選一個就行了。通常,一個演算法在其執行過程中要做很多選擇。如果一個好的選擇的獲益大於壞的選擇的代價,那麼隨機地做一個選擇就能得到一個很有效的演算法。我們在前文已經了解到,對快速排序來說,一組好壞相雜的劃分仍能產生很好的運行時間 。因此我們可以認為該演算法的隨機化版本也能具有較好的性態。

④ 關於快速排序C語言演算法

//一點小問題而已,已為你改好
#include <stdio.h>
void Quick_sort (int s[], int l, int r )
{
if(l<r)
{
int i=l,j=r,x=s[l];
while(i<j)
{
while(i<j&&s[j]>=x)
{j--;}//從右向左找第一個小於x的數
if(i<j)
{s[i++]=s[j];}
while(i<j&&s[i]<=x)
{i++;}//從左到右找第一個大於等於x的數
if(i<j)
{s[j--]=s[i];}
}
s[i]=x;
Quick_sort(s,l,i-1);//遞歸
Quick_sort(s,i+1,r);
}
}
int main()
{
int arr[7] = { 1,9,7,6,5,35,15 };
int i;
printf("之前的數組:");
for (i = 0; i < 7; i++) printf("%3d", arr[i]);
printf("\n");
Quick_sort(arr, 0, 6);
printf("排序之後的數組:");
for (i = 0; i < 7; i++) printf("%3d", arr[i]);
printf("\n");
return 0;
}

⑤ 快速排序演算法

快速排序(Quicksort)是對冒泡排序的一種改進。

然後,左邊和右邊的數據可以獨立排序。對於左側的數組數據,又可以取一個分界值,將該部分數據分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側的數組數據也可以做類似處理。

重復上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側部分排好序後,再遞歸排好右側部分的順序。當左、右兩個部分各數據排序完成後,整個數組的排序也就完成了。

快速排序演算法通過多次比較和交換來實現排序,其排序流程如下:

(1)首先設定一個分界值,通過該分界值將數組分成左右兩部分。

(2)將大於或等於分界值的數據集中到數組右邊,小於分界值的數據集中到數組的左邊。此時,左邊部分中各元素都小於或等於分界值,而右邊部分中各元素都大於或等於分界值。


⑥ 用C語言編程實現快速排序演算法

給個快速排序你參考參考

/**********************快速排序****************************
基本思想:在待排序的n個記錄中任取一個記錄(通常取第一個記錄),
以該記錄為基準,將當前的無序區劃分為左右兩個較小的無
序子區,使左邊的記錄均小於基準值,右邊的記錄均大於或
等於基準值,基準值位於兩個無序區的中間位置(即該記錄
最終的排序位置)。之後,分別對兩個無序區進行上述的劃
分過程,直到無序區所有記錄都排序完畢。
*************************************************************/

/*************************************************************
函數名稱:staticvoidswap(int*a,int*b)
參數:int*a---整型指針
int*b---整型指針
功能:交換兩個整數的位置
返回值:無
說明:static關鍵字指明了該函數只能在本文件中使用
**************************************************************/
staticvoidswap(int*a,int*b)
{
inttemp=*a;
*a=*b;
*b=temp;
}

intquickSortNum=0;//快速排序演算法所需的趟數
/*************************************************************
函數名稱:staticintpartition(inta[],intlow,inthigh)
參數:inta[]---待排序的數據
intlow---無序區的下限值
inthigh---無序區的上限值
功能:完成一趟快速排序
返回值:基準值的最終排序位置
說明:static關鍵字指明了該函數只能在本文件中使用
**************************************************************/
staticintpartition(inta[],intlow,inthigh)
{
intprivotKey=a[low];//基準元素
while(low<high)
{//從表的兩端交替地向中間掃描
while(low<high&&a[high]>=privotKey)//找到第一個小於privotKey的值
high--;//從high所指位置向前搜索,至多到low+1位置
swap(&a[low],&a[high]);//將比基準元素小的交換到低端

while(low<high&&a[low]<=privotKey)//找到第一個大於privotKey的值
low++;//從low所指位置向後搜索,至多到high-1位置
swap(&a[low],&a[high]);//將比基準元素大的交換到高端
}
quickSortNum++;//快速排序趟數加1
returnlow;//返回基準值所在的位置
}

/*************************************************************
函數名稱:voidQuickSort(inta[],intlow,inthigh)
參數:inta[]---待排序的數據
intlow---無序區的下限值
inthigh---無序區的上限值
功能:完成快速排序演算法,並將排序完成的數據存放在數組a中
返回值:無
說明:使用遞歸方式完成
**************************************************************/
voidQuickSort(inta[],intlow,inthigh)
{
if(low<high)
{
intprivotLoc=partition(a,low,high);//將表一分為二
QuickSort(a,low,privotLoc-1);//遞歸對低子表遞歸排序
QuickSort(a,privotLoc+1,high);//遞歸對高子表遞歸排序
}
}
熱點內容
手機店設置的初始密碼一般是多少 發布:2025-05-11 09:33:15 瀏覽:400
昂科威選擇哪個配置 發布:2025-05-11 09:25:50 瀏覽:35
怎麼解決安卓視頻全屏卡頓 發布:2025-05-11 09:14:55 瀏覽:725
匯編從編譯到執行 發布:2025-05-11 09:09:04 瀏覽:257
安卓系統低版本如何升級 發布:2025-05-11 09:04:44 瀏覽:251
認證類型加密演算法 發布:2025-05-11 08:58:35 瀏覽:561
android停靠 發布:2025-05-11 08:42:23 瀏覽:646
超時代加密 發布:2025-05-11 08:41:29 瀏覽:780
為什麼還要輸入支取密碼 發布:2025-05-11 08:32:24 瀏覽:362
資料庫課程設計案例 發布:2025-05-11 08:15:33 瀏覽:51