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
分析:
快速排序是一个不稳定的排序方法。