1. 快速排序:快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比一部分的关键字小,比另一部分的关键字大,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
2. 双路快速排序的时间,空间复杂度及稳定性:
1>. 时间复杂度:O(nlogn);因为我们这里双路快速排序的过程中向下递归分割数组的过程时间复杂度为:O(logn);我们在划分数组部分的时候还要遍历数组,时间复杂度为:O(n);因此双路快速排序的时间复杂度为:O(nlogn)。
2>. 空间复杂度:S(1);因为我们在双路快速排序时是对原数组进行直接排序,并没有其他创建新的数组。
3>. 稳定性: 稳定;我们在双路快速排序时,并不会出现大跨度的交换元素。
3. 双路快速排序的实现
//双路快速排序
/*
* 我们每次递归将数组分为两部分 小于指定元素 大于指定元素两部分
* L表示数组左端位置 R表示数组右端位置 p表示最后分完指定元素的位置
* 小于指定元素:[L + 1, p - 1]
* 大于指定元素:[p + 1, R]
* 双路快速排序中划分数组时 我们不需要管与指定元素相等的元素v
* 只需要将与v相等的元素划分到小于v的部分 或者 划分到大于v的部分即可
* 先使i从L+1开始向后遍历 再使j从R开始向前遍历
* 当i位置的元素不小于v时 i就暂时停在当前位置 否则i后移即可
* 然后从j开始 当j位置的元素不大于v时 j就暂停在当前位置 否则j前移即可
* 当i j都暂停时 交换i j位置的元素 使不小于v(当前i位置)的元素 与 不大于v的元素(当前j位置)的元素交换位置
* 然后分别更新i j的值 使i后移 j前移
* 直到i大于j时 循环结束
* 最后交换j位置和L位置(v)的元素(即将指定元素换在小于等于指定元素 和 大于等于指定元素之间)
* 并返回最后元素v的索引
*/
public class QuickSort02 {
public static void main(String[] args) {
int[] arr = {2, 3, 1, 7, 4, 6, 4, 5, 8, 10};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
//双路快速排序
private static void quickSort(int[] arr, int L, int R) {
if(L > R) { //判断递归临界条件
return;
}
//对数组向下划分 返回那个选出的元素v的位置
int p = partition(arr, L, R);
quickSort(arr, L, p - 1); //向下递归 从原数组左端 到v元素位置减1的位置(表示小于等于v元素的全部元素的下标范围)
quickSort(arr, p + 1, R); //向下递归 从原数组v元素位置加1 到原数组左端(表示大于等于v元素的全部元素的下标范围)
}
//对数组进行划分 使选出的v元素右边部分的元素包括小于等于v的 v元素左边部分的元素包括大于等于v的
private static int partition(int[] arr, int L, int R) {
//获取指定元素
// int v = arr[L];
/*
* 优化一下 随机让后面的数字和第一个数字换一下
* 尽量避免极端情况(一直递增的数组 如果是一直递增的数组 时间复杂度就为O(n^2))
*/
swap(arr, L, (int) (Math.random() * (R - L + 1) + L));
int v = arr[L];
int i = L + 1;
int j = R;
while(true) {
while(i <= R && arr[i] < v) {
i++;
}
while(j >= L && arr[j] > v) {
j--;
}
if(i > j) {
break;
}
swap(arr, i, j);
i++;
j--;
}
swap(arr, L, j);
return j;
}
//交换数组中指定位置的两个元素
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
4. 运行结果: