五十道程式設計小題目 --- 28 八大排序演算法 java 之 06快速排序
6. 交換排序—快速排序(Quick Sort)
快速排序演算法介紹
快速排序和歸併排序都使用分治法來設計演算法,區別在於歸併排序把陣列分為兩個基本等長的子陣列,分別排好序之後還要進行歸併(Merge)操作,而快速排序拆分子陣列的時候顯得更有藝術,取一個基準元素,拆分之後基準元素左邊的元素都比基準元素小,右邊的元素都不小於基準元素,這樣只需要分別對兩個子陣列排序即可,不再像歸併排序一樣需要歸併操作。
基本思想:
1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,
2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。
3)此時基準元素在其排好序後的正確位置
4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。
快速排序的示例:
(a)一趟排序的過程:
(b)排序的全過程
演算法的實現:
import java.util.Random; public class QuickSort { // 快速排序 private static void quickSort(int[] a) { System.out.println("在陣列中從0到"+(a.length-1)+"基準元素索引:" + 0); subQuickSort(a, 0, a.length-1); } private static void subQuickSort(int[] a,int start, int end) { if(a == null || end-start<2){ return ; } int keyIndex = quickSortPortion(a, start, end); System.out.println("在陣列中從"+start+"到"+end+"基準元素索引變換:" + keyIndex); if(keyIndex == start){ subQuickSort(a, start+1, end); }else if(keyIndex == end){ subQuickSort(a, start, end-1); }else{ subQuickSort(a, start, keyIndex-1); subQuickSort(a, keyIndex+1, end); } } private static int quickSortPortion(int[] a, int start, int end) { int minIndex = (end-start) / 2 + start; // minIndex定義為陣列的中間索引 int key = start; // 將陣列的第一個元素的索引定義為基準元素 int h = end; System.out.println("快速排序------------>"); for (int i = start; i < end; i++) { // 比較 length-1次 if (key <= minIndex) { // 如果基準元素在前半部分 if (a[key] > a[h]) { // 元素值比基準元素值小 swap(a, key, h); // 交換位置 int tmp = h; h = key + 1; key = tmp; } else { h--; } } else { // 如果基準元素在後半部分 if (a[key] < a[h]) { // 元素值比基準元素值大 swap(a, key, h); // 交換位置 int tmp = key; key = h; h = tmp - 1; } else { h++; } } print(a); } // print(a); return key; } // 交換陣列元素 private static void swap(int[] arr, int i, int j) { if (i == j) { return; } arr[i] = arr[i] + arr[j]; arr[j] = arr[i] - arr[j]; arr[i] = arr[i] - arr[j]; } // 列印陣列 public static void print(int[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 }; System.out.println("排序前 : "); print(a); System.out.println("排序 : "); quickSort(a); print(a); // System.out.println("任意陣列測試:"); // Random r = new Random(); // int[] testArr = new int[20]; // for (int i = 0; i < 20; i++) { // testArr[i] = r.nextInt(100); // } // // System.out.println("排序前 : "); // print(testArr); // // System.out.println("排序後: "); // print(quickSort(testArr)); } }
輸出結果:
排序前 : 49 38 65 97 76 13 27 49 排序後 : 在陣列中從0到7基準元素索引:0 快速排序------------> 49 38 65 97 76 13 27 49 27 38 65 97 76 13 49 49 27 38 65 97 76 13 49 49 27 38 49 97 76 13 65 49 27 38 13 97 76 49 65 49 27 38 13 49 76 97 65 49 27 38 13 49 76 97 65 49 在陣列中從0到7基準元素索引變換:3 快速排序------------> 13 38 27 49 76 97 65 49 13 27 38 49 76 97 65 49 在陣列中從0到2基準元素索引變換:1 快速排序------------> 13 27 38 49 49 97 65 76 13 27 38 49 49 76 65 97 13 27 38 49 49 65 76 97 在陣列中從4到7基準元素索引變換:6 13 27 38 49 49 65 76 97
分析:
快速排序是一個不穩定的排序方法。
6. 交換排序—快速排序(Quick Sort)
快速排序演算法介紹
快速排序和歸併排序都使用分治法來設計演算法,區別在於歸併排序把陣列分為兩個基本等長的子陣列,分別排好序之後還要進行歸併(Merge)操作,而快速排序拆分子陣列的時候顯得更有藝術,取一個基準元素,拆分之後基準元素左邊的元素都比基準元素小,右邊的元素都不小於基準元素,這樣只需要分別對兩個子陣列排序即可,不再像歸併排序一樣需要歸併操作。
基本思想:
1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,
2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。
3)此時基準元素在其排好序後的正確位置
4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。
快速排序的示例:
(a)一趟排序的過程:
(b)排序的全過程
演算法的實現:
import java.util.Random;
public class QuickSort {
// 快速排序
private static void quickSort(int[] a) {
System.out.println("在陣列中從0到"+(a.length-1)+"基準元素索引:" + 0);
subQuickSort(a, 0, a.length-1);
}
private static void subQuickSort(int[] a,int start, int end) {
if(a == null || end-start<2){
return ;
}
int keyIndex = quickSortPortion(a, start, end);
System.out.println("在陣列中從"+start+"到"+end+"基準元素索引變換:" + keyIndex);
if(keyIndex == start){
subQuickSort(a, start+1, end);
}else if(keyIndex == end){
subQuickSort(a, start, end-1);
}else{
subQuickSort(a, start, keyIndex-1);
subQuickSort(a, keyIndex+1, end);
}
}
private static int quickSortPortion(int[] a, int start, int end) {
int minIndex = (end-start) / 2 + start; // minIndex定義為陣列的中間索引
int key = start; // 將陣列的第一個元素的索引定義為基準元素
int h = end;
System.out.println("快速排序------------>");
for (int i = start; i < end; i++) { // 比較 length-1次
if (key <= minIndex) { // 如果基準元素在前半部分
if (a[key] > a[h]) { // 元素值比基準元素值小
swap(a, key, h); // 交換位置
int tmp = h;
h = key + 1;
key = tmp;
} else {
h--;
}
} else { // 如果基準元素在後半部分
if (a[key] < a[h]) { // 元素值比基準元素值大
swap(a, key, h); // 交換位置
int tmp = key;
key = h;
h = tmp - 1;
} else {
h++;
}
}
print(a);
}
// print(a);
return key;
}
// 交換陣列元素
private static void swap(int[] arr, int i, int j) {
if (i == j) {
return;
}
arr[i] = arr[i] + arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];
}
// 列印陣列
public static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
System.out.println("排序前 : ");
print(a);
System.out.println("排序 : ");
quickSort(a);
print(a);
// System.out.println("任意陣列測試:");
// Random r = new Random();
// int[] testArr = new int[20];
// for (int i = 0; i < 20; i++) {
// testArr[i] = r.nextInt(100);
// }
//
// System.out.println("排序前 : ");
// print(testArr);
//
// System.out.println("排序後: ");
// print(quickSort(testArr));
}
}
輸出結果:
排序前 :
49 38 65 97 76 13 27 49
排序後 :
在陣列中從0到7基準元素索引:0
快速排序------------>
49 38 65 97 76 13 27 49
27 38 65 97 76 13 49 49
27 38 65 97 76 13 49 49
27 38 49 97 76 13 65 49
27 38 13 97 76 49 65 49
27 38 13 49 76 97 65 49
27 38 13 49 76 97 65 49
在陣列中從0到7基準元素索引變換:3
快速排序------------>
13 38 27 49 76 97 65 49
13 27 38 49 76 97 65 49
在陣列中從0到2基準元素索引變換:1
快速排序------------>
13 27 38 49 49 97 65 76
13 27 38 49 49 76 65 97
13 27 38 49 49 65 76 97
在陣列中從4到7基準元素索引變換:6
13 27 38 49 49 65 76 97
分析:
快速排序是一個不穩定的排序方法。