交换类排序
- 基本思想:对待排序记录的关键字两两进行比较,只要发现两个记录为逆序就进行交换,直到没有逆序的记录为止。(如果要将整个记录序列调整为递增序列,那么关键字之间是递减关系即为逆序。)
快速排序基于分治策略思想。属于交换类排序。
分治策略基本思想:将原问题分解为若干个规模更小但结构与原问题相似的问题递归地解决这些子问题,然后将这些子问题的解组合为原问题的解。
快速排序基本思想
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都小于等于另外一部分的所有数据,然后再按此方法对这两部分数据分别进行快速排序,整个过程可以递归进行,以此达到整个数据变成有序序列。
基本做法
从待排序列中任意选择一个记录,以该记录的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移动至该记录之前,关键字大于等于枢轴的记录均移动至该记录之后。致使一趟排序之后,记录的无序序列K[0……n-1]将分割成左右两个子序列,然后分别对分割所得两个序列递归地进行快速排序,以此类推,直至每个子序列中只含一个记录为止。
一趟快速排序步骤
- 设置两个变量low、high,分别为待排序列数组的第一个和最后一个元素下标,即,low = 0,high = arr.length-1;
- 从待排序列中任意选择一个记录作为“枢轴”,一般选第一个关键字作为枢轴,即key = arr[low];
- 用下标为high的记录和key比较,如果arr[high] >= key,则high继续逆向向前搜索,直到找到小于key的记录arr[high],放到下标为low的arr[low]位置(没必要和arr[low]交换,因为此时arr[low]的值被保存在了key中,已有备份,不会丢失);
- 用下标为low的记录和key比较,如果arr[low] < key,则low继续正向向后搜索,直到找到大于等于key的记录arr[low],放到下标为high的arr[high]位置(没必要和arr[high]交换,因为此时arr[high]的值已有备份,不会丢失);
- 重复第3、4步,直到low与high交汇,即,low == high,把枢轴值放到交汇处的记录上,即arr[low] = key。
具体实现
待排序列为{6, 1, 8, 3, 5, 9, 2},给出快速排序的完整过程。
步骤一:设置变量low、high。
步骤二:选择枢轴。
步骤三:arr[high]与枢轴值key比较,若arr[high] >= key,high继续逆向向前搜索;否则,arr[low] = arr[high]。
步骤四:arr[low]与枢轴值key比较,若arr[low] < key,low继续正向向后搜索;否则,arr[high] = arr[low]。
继续正向向后搜索。
继续正向向后搜索。
步骤五:重复。
重复步骤三。
继续逆向向前搜索。
继续逆向向前搜索。
重复步骤四。
继续正向向前搜索。
继续正向向前搜索。
low与high交汇。arr[low] = key。
此时,一趟快速排序完成。以此时key = 6把待排序列分成两部分,key = 6前面都是小于key的值,后面都是大于等于key的值。
然后将代排序列分割成左右两个子序列,分别对分割所得两个子序列递归地进行快速排序,以此类推,直到每个子序列中只含有一个记录为止。
该序列快速排序的各趟结果如下:
在第三趟排序之后,每个子序列都只有一个记录了。此时,发现序列已经成为有序序列了。
代码实现
public class QuickSort {
/**
* 一趟快速排序
* @param arr
* @param low
* @param high
* @return
*/
private static int oneQuickSort(int[] arr, int low, int high) {
int key = arr[low];
while(low < high) {
while(low < high && arr[high] >= key) {
high--;
}
arr[low] = arr[high];
while(low < high && arr[low] < key) {
low++;
}
arr[high] = arr[low];
}
arr[low] = key;
return low;
}
/**
* 快速排序核心
* @param arr
* @param low
* @param high
*/
public static void quickSort(int[] arr, int low, int high) {
if(null == arr) {
return;
}
if(low < high) {
//一趟快速排序得到枢轴下标
int mid = oneQuickSort(arr, low, high);
//对左右子序列进行递归
quickSort(arr, low, mid-1);
quickSort(arr, mid+1, high);
}
}
private static void showArr(int[] arr) {
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void main(String[] args) {
int[] arr = {6, 1, 8, 3, 5, 9, 2};
/**
* 快速排序
* 先设置变量low、high
* low = 0
* high = arr.length-1
*/
quickSort(arr, 0, arr.length-1);
showArr(arr);
}
}
运行结果
效率
时间复杂度:O(nlogn);
空间复杂度:O(logn);
稳定性:不稳定排序。
说明:logn是以2为底n的对数