1. 程式人生 > >Java實現快速排序(快排)

Java實現快速排序(快排)

快速排序是氣泡排序的改進版,也是最好的一種內排序,在很多面試題中都會出現,也是作為程式設計師必須掌握的一種排序方法。

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

下面我們用圖解來說明一下這個排序演算法

假設使用者輸入瞭如下陣列:

下標

0

1

2

3

4

5

資料

6

2

7

3

8

9

建立變數i=0(指向第一個資料), j=5(指向最後一個數據), k=6(賦值為第一個資料的值)。

我們要把所有比k小的數移動到k的左面,所以我們可以開始尋找比6小的數,從j開始,從右往左找,不斷遞減變數j的值,我們找到第一個下標3的資料比6小,於是把資料3移到下標0的位置,把下標0的資料6移到下標3,完成第一次比較:

下標

0

1

2

3

4

5

資料

3

2

7

6

8

9

i=0 j=3 k=6

接著,開始第二次比較,這次要變成找比k大的了,而且要從前往後找了。遞加變數i,發現下標2的資料是第一個比k大的,於是用下標2的資料7和j指向的下標3的資料的6做交換,資料狀態變成下表:

下標

0

1

2

3

4

5

資料

3

2

6

7

8

9

i=2 j=3 k=6

稱上面兩次比較為一個迴圈。

接著,再遞減變數j,不斷重複進行上面的迴圈比較。

在本例中,我們進行一次迴圈,就發現i和j“碰頭”了:他們都指向了下標2。於是,第一遍比較結束。得到結果如下,凡是k(=6)左邊的數都比它小,凡是k右邊的數都比它大:

下標

0

1

2

3

4

5

資料

3

2

6

7

8

9

如果i和j沒有碰頭的話,就遞加i找大的,還沒有,就再遞減j找小的,如此反覆,不斷迴圈。注意判斷和尋找是同時進行的。

然後,對k兩邊的資料,再分組分別進行上述的過程,直到不能再分組為止。

注意:第一遍快速排序不會直接得到最終結果,只會把比k大和比k小的數分到k的兩邊。為了得到最後結果,需要再次對下標2兩邊的陣列分別執行此步驟,然後再分解陣列,直到陣列不能再分解為止(只有一個數據),才能得到正確結果。

下面,我們用一個動圖,請大家耐心看完

接下來我們用程式碼實現

package quickSort;

public class QuickSort {
	private static int count;
	/**
	 * 測試
	 * @param args
	 */
	public static void main(String[] args) {
		int[] num = {3,45,78,64,52,11,64,55,99,11,18};
		System.out.println(arrayToString(num,"未排序"));
		QuickSort(num,0,num.length-1);
		System.out.println(arrayToString(num,"排序"));
		System.out.println("陣列個數:"+num.length);
		System.out.println("迴圈次數:"+count);
		
	}
	/**
	 * 快速排序
	 * @param num	排序的陣列
	 * @param left	陣列的前針
	 * @param right 陣列後針
	 */
	private static void QuickSort(int[] num, int left, int right) {
		//如果left等於right,即陣列只有一個元素,直接返回
		if(left>=right) {
			return;
		}
		//設定最左邊的元素為基準值
		int key=num[left];
		//陣列中比key小的放在左邊,比key大的放在右邊,key值下標為i
		int i=left;
		int j=right;
		while(i<j){
			//j向左移,直到遇到比key小的值
			while(num[j]>=key && i<j){
				j--;
			}
			//i向右移,直到遇到比key大的值
			while(num[i]<=key && i<j){
				i++;
			}
			//i和j指向的元素交換
			if(i<j){
				int temp=num[i];
				num[i]=num[j];
				num[j]=temp;
			}
		}
		num[left]=num[i];
		num[i]=key;
		count++;
		QuickSort(num,left,i-1);
		QuickSort(num,i+1,right);
	}
	/**
	 * 將一個int型別陣列轉化為字串
	 * @param arr
	 * @param flag
	 * @return
	 */
	private static String arrayToString(int[] arr,String flag) {
		String str = "陣列為("+flag+"):";
		for(int a : arr) {
			str += a + "\t";
		}
		return str;
	}

}

 輸出結果為:

陣列為(未排序):3	45	78	64	52	11	64	55	99	11	18	
陣列為(排序):3	11	11	18	45	52	55	64	64	78	99	
陣列個數:11
迴圈次數:8