算法题解:快速排序算法(单边指针)
算法概述
快速排序(Quicksort),又称划分交换排序,简称快排,一种排序算法,最早由东尼·霍尔提出。在平均状况下,排序n个项目要O(n log n)次比较。在最坏状况下则需要O(n^2)次比较,但这种状况并不常见。
事实上,快速排序O(n log n)通常明显比其他算法更快,因为它的内部循环可以在大部分的架构上很有效率地达成。
算法流程
快速排序使用分治法策略来把一个序列分为较小和较大的2个子序列,然后递归地排序两个子序列。
步骤为:
-
挑选基准值:从数列中挑出一个元素,称为“基准”(pivot),
-
分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成,
-
递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。
递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。
选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。
算法步骤
快速排序的算法步骤我给划分为5步:
- 递归终止条件
- 定义头尾指针与基准值
- 把小于基准数的移到左边
- 继续处理左边的
- 继续处理右边的
示例代码
public class QuickSort {
public static void quickSort(int[] arr, int left, int right) {
// 递归的边界
if (left < right) {
int partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
}
private static int partition(int[] arr, int left, int right) {
// 选择首元素为基准值(pivot)
int pivot = arr[left];
// 创建标记 mark 指针
int markPoint = left;
// 排除基准值后逐个遍历
for (int i = left + 1; i <= right; i++) {
// 如果比基准值小,则 mark++ 后互换
if (arr[i] < pivot) { // 小于:从小到大;大于:从大到小
markPoint++;
swap(arr, i, markPoint);
}
}
// 将首元素基准值与当前 mark 互换, 即基准值的坐边都是比基准值小的
swap(arr, left, markPoint);
return markPoint;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {0, 0, 1, 2, 4, 2, 2, 3, 1, 4};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}
打印输出:
[0, 0, 1, 1, 2, 2, 2, 3, 4, 4]
复杂度分析
时间复杂度
数组有n个元素,因为要递归运算,算出支点pivot的位置,然后递归调用左半部分和有半部分,这个时候理解上是若第一层的话就是n/2、n/2,若是第二层就是n/4、n/4、n/4、n/4这四部分,即n个元素理解上是一共有几层2^k=n,k=log2(n),然后每层都是n的复杂度,那么平均就是O(nlog n)的时间复杂度。但这种肯定是平均情况,如果你是标准排序的情况下,如果已经是升序的顺序,那么递归只存在右半部分了,左半部分都被淘汰了。(n-1)(n-2)….*1,这个复杂度肯定就是O(n^2)。
空间复杂度
快排的实现是递归调用的, 而且每次函数调用中只使用了常数的空间,因此空间复杂度等于递归深度。
最好的情况最多需要O(log2 n)次的嵌套递归调用,所以它需要O(log n)的空间。最坏情况下需要O(n)次嵌套递归调用,因此需要O(n)的空间。
时间复杂度引用自知乎
https://www.zhihu.com/question/22393997/answer/189896378
版权声明:凡未经本网站书面授权,任何媒体、网站及个人不得转载、复制、重制、改动、展示或使用本网站的局部或全部的内容或服务,或在非本网站所属服务器上建立镜像。如果已转载,请自行删除。同时,我们保留进一步追究相关行为主体的法律责任的权利。我们希望与各媒体合作,签订著作权有偿使用许可合同,故转载方须书面/邮件申请,以待商榷。