程序员面试必备(一) —— Quicksort
1 介绍
快速排序(Quicksort)是C.A.R.Hoare于1960年提出的,它的基本思想是通过一趟排序将待排序的数据分成独立的两部分,其中一部分的数据全部小于另一部分的数据,然后按照上述思想再分别对每部分进行分割排序,整个过程递归进行。(来源于百度)
2 原理
快排真的很容易在面试中遇到,为了更加直观具体,小鱼要举例说明啦~认真听讲哦!
Step1:选取第一个元素为标记值,设置两个变量于待排数据的第一个元素和最后一个元素,如图1所示。
10 |
4 |
2 |
6 |
5 |
19 |
11 |
8 |
3 |
i |
j |
Step2:先将j向左移动,直至选取到小于标志位数值(10)的元素,停止,如图2所示,刚好5<10,所以j相当于不移动。
10 |
4 |
2 |
6 |
5 |
19 |
11 |
8 |
3 |
i |
j |
Step3:将i向右移动,直至选取到大于标志位数值的元素,停止,如图3所示。
10 |
4 |
2 |
6 |
5 |
19 |
11 |
8 |
3 |
i |
j |
Step4:交换i和j指向的元素数值,结果如图4所示,继续重复Step2和Step3,直至i和j相遇,结果如图5所示。
10 |
4 |
2 |
6 |
5 |
3 |
11 |
8 |
19 |
i |
j |
10 |
4 |
2 |
6 |
5 |
3 |
8 |
11 |
19 |
|
i&j |
Step5:将i与j共同指向的元素和标志位交换,至此完成一趟快速排序,以标志位为分隔将待排数据分成独立的两部分,得到图6所示结果。
8 |
4 |
2 |
6 |
5 |
3 |
10 |
11 |
19 |
Step6:运用递归,对每个独立部分重复Step1至Step5步骤,至所有数据排成有序数组。
附java实现代码
public void quickSort(int[] arr,int left,int right){
if(left > right){
return;
}
int i = left; // 定位i
int j = right; // 定位j
int temp = arr[left]; // 选取标志位
while( i < j){
while(arr[j] >= temp && i<j){
j--; // j先左移寻找第一个小于标志位的元素
}
while(arr[i] <= temp && i<j){
i++; // i右移寻找第一个大于标志位的元素
}
// 交换
int t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
// i和j相遇时,与标志位交换
arr[left] = arr[j];
arr[i] = temp;
// 递归--对两个独立部分按上述思想进行分别排序
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
}
为什么要j先移动,i先移动有什么后果?
若先移动i,无法保证最终i与j相遇的地方一定是小于标志位的,这样的情况下,标志位与其对应元素交换,无法达到标志位左侧数据全部小于标志位。本例中即使如此,感兴趣可以自己尝试一下哦!
-
快排的时间空间复杂度? 快速排序最坏的情况是选择的标志位都是当前序列的最大值或最小值,此时快速排序退化为冒泡排序,时间复杂度为O(N2),其平均时间复杂度为O(NlogN)。快速排序的空间复杂度即递归树的高度,最好情况下为O(logN),最坏情况下为O(N),平均空间复杂度为O(logN)。
-
标志选取如何避免出现排序效率最差的情况? 为了避免取到序列最大值或最小值最为标记位,可用“三数取中法”获取标记位。
Tip: https://visualgo.net/en/sorting这个网站可以将算法执行过程动态可视化哟,不仅快速排序,还有很多种常见易考的算法。
快排适合数据量N较大时应用,且当待排元素是随机分布时,快速排序最好哦。好啦,今天的快排就这样吧,下次再见!(时间未知)