數組——快速排序法(遞歸)

快速排序算法
快速排序(Quicksort)是對冒泡排序的一種改進。由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(通常選用數組的第一個數)作爲關鍵數據,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱爲一趟快速排序。值得注意的是,快速排序不是一種穩定的排序算法,也就是說,多個相同的值的相對位置也許會在算法結束時產生變動。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作爲關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j--),找到第一個小於key的值A[j],將A[j]賦給A[i];
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]賦給A[j];
5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[j]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到爲止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)。
排序演示
假設用戶輸入瞭如下數組:
下標
0
1
2
3
4
5
數據
6
2
7
3
8
9
創建變量i=0(指向第一個數據), j=5(指向最後一個數據), k=6(賦值爲第一個數據的值)。
我們取走了下標0的數據,於是,我們需要找到一個數字來替換他。由於我們要把所有比6小的數移動到左面,所以我們可以開始尋找比6小的數並從右往左找。別急,我們要按順序找哦。不斷遞減j的值,我們發現下標3的數據比6小,於是把3移到下標0(實際是i指向的位置。代碼中要用i,因爲後面還會循環這個步驟,不用i的話第二次循環就會出問題。),數組和變量變成了以下狀態:
下標
0
1
2
3
4
5
數據
3
2
7
6
8
9
i=0 j=3 k=6
由於變量k已經儲存了下標0的數據,所以我們可以放心的把下標0覆蓋了。如此一來,下標3雖然有數據,但是相當於沒有了,因爲數據已經複製到別的地方了。於是我們再找一個數據來替換他。這次要變成找比k大的了,而且要從前往後找了。遞加變量i,發現下標2是第一個比k大的,於是用下標2的數據7替換j指向的下標3的數據,數據狀態變成下表:
下標
0
1
2
3
4
5
數據
3
2
6
7
8
9
i=2 j=3 k=6
重複上面的步驟,遞減變量j。這時,我們發現i和j“碰頭”了:他們都指向了下標2。於是,循環結束,把k填回下標2裏,即得到結果。
如果i和j沒有碰頭的話,就遞加i找大的,還沒有,就再遞減j找小的,如此反覆,不斷循環。注意判斷和尋找是同時進行的。
注意:快速排序不會直接得到最終結果,只會把比k大和比k小的數分到k的兩邊。(你可以想象一下i和j是兩個機器人,數據就是大小不一的石頭,先取走i前面的石頭留出迴旋的空間,然後他們輪流分別挑選比k大和比k小的石頭扔給對面,最後在他們中間把取走的那塊石頭放回去,於是比這塊石頭大的全扔給了j那一邊,小的全扔給了i那一邊。只是這次運氣好,扔完一次剛好排整齊。)爲了得到最後結果,需要再次對下標2兩邊的數組分別執行此步驟,然後再分解數組,直到數組不能再分解爲止(只有一個數據),才能得到正確結果。
下面用兩幅圖來直觀的瞭解快排的算法原理:
數組——快速排序法(遞歸) - YuJar - Jar
 
數組——快速排序法(遞歸) - YuJar - Jar
 

import java.util.*;
class QuickSort{
//快速排序法
public void sort(int left, int right, int array[]){
int l = left;
int r = right;
int midVal = array[(l+r)/2]; //用中間的元素值做爲比較的中間值
int temp = 0;
while(l<r){
while(array[l]<midVal){
l++;
}
while(array[r]>midVal){
r--;
}
if(l>=r){
break;
}
temp = array[l];
array[l] = array[r];
array[r] = temp;
//相等的情況也必須判定必處理
if(array[l] == midVal){
r--;
}
if(array[r] == midVal){
++l;
}
}
if(l==r){
++l;
--r;
}
//這裏用到遞歸的思想
if(left<r){
sort(left, r, array);//傳入數組第一個元素下標0與當前r的值。
}
if(right>l){
sort(l, right, array);//傳入數組當前r的值與數組最後一個元素的下標。
}
}
}

class Test{
public static void main(String args[]){
int array[] = new int[13];
System.out.println("生成13個0~99的隨機數:");
for(int i=0; i<array.length; i++){
array[i] = (int)(Math.random()*100);
System.out.print(array[i]+" ");
}
QuickSort qs = new QuickSort();
qs.sort(0, array.length-1, array); //傳入數組首尾元素的下標與數組引用
System.out.println("\n用快速排序法排序後爲:");
for(int i=0; i<array.length; i++){
System.out.print(array[i]+" ");
}

}
}
/********************************
生成13個0~99的隨機數:
34 8 1 81 35 35 46 96 4 25 75 93 59
用快速排序法排序後爲:
1 4 8 25 34 35 35 46 59 75 81 93 96
********************************/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章