2021春招时间到了,面试也越来越多,手撕快排也是腾讯、阿里、字节等大厂所必备的知识,在面试过程中,能够正确讲出快排原理与使用代码实现快速排序也是面试的重点复习之一,话不多说,直接进入今日主题:快速排序
今日主题:快速排序
不介绍快速排序了,直插重点
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用
快速排序的时间复杂度为
一、快速排序的思想
- 通过一趟排序:将待排数组分成两个部分,左边部份均小于右边部分,则可以再对这两部分记录进行再排序,以达到整个序列有序
- 设置两个变量left = 0, right = 数组长度-1
- 选取数组第一个数为key基准数(此处可理解成为挖坑操作,即待后面的数据来补坑),因为选择的第一个数为基准数,按照升序排序的话,前面的数需要比基准数小,后面的数要比基准数大。
- 即完成5、6步骤后,需要满足,基准数的新位置前面的数要小于它,后面的数要大于它
- 故先从后面往前搜索(right–),直到找到第一个小于key(基准数、也为坑),然后将该数放到刚刚挖的坑上面,将前面的坑填满,实现0~left的坑满足 < 基准数,即arr[left] = arr[right],👇5操作
- 第四个步骤又挖了一个坑给我,要我从前往后找,要找一个比基准数大的数才能填这个坑,因为要实现0~left的数 < 基准数 && right~(数组长度-1)的数 >= 基准数,即left++,直到arr[left] > key,然后继续完成填坑操作,即arr[right] = arr[left]。也相当于实现了挖坑的操作。重复操作4、5.直到left >= right才中止第一次基准数的正确位置排序
- 然后将基准数的新位置进行补坑处理,即一个数已经在排序中确定其正确位置了。
- 再对这个位置的前后两部分进行相同的快速排序处理
- 直至边界left >= right才分别中止快速排序操作
- 得到有序数列
运行结果
二、快速排序的两种代码实现(同理)
1.获取基准数位置+双区间递归分开
在代码实现这块,建议读者先将快速排序(不断的挖坑)和递归实现先分开代码实现先,再通过理解代码,将这两块进行合起来,完成最终的快速排序算法实现。
代码如下(示例):
#include <stdio.h>
#include <algorithm>
/*
快速排序
选第一个为基准数,不断挖坑,
1.从后往前对比,第一个比基准数小的移到low位置
2.从前往后对比,第一个比基准数大的移到上面那个的位置
3.重复2、3操作,直至low==high或low>high
4.再对其它区间进行同样操作
*/
/* 获取基准数在数组排序中处于的位置 */
int getStandard(int arr[], int i,int j)
{
//获取基准数,挖坑
int cur = arr[i];
while(i < j)
{
//注意边界判定
while(i < j && arr[j] >= cur)
j--;
if(arr[j] < cur){
arr[i] = arr[j];
}
while(i < j && arr[i] < cur)
i++;
if(arr[i] > cur){
arr[j] = arr[i];
}
}
//基准数归位
arr[i]=cur;
//返回基准数目前位置,将其左右再进行快速排序
return i;
}
void quicksort(int arr[], int low, int high)
{
if( low < high )
{
int standard = getStandard(arr, low, high);
//对左右剩余的两个区间进行相同操作
quicksort(arr, low, standard-1);
quicksort(arr, standard+1, high);
}
}
int main()
{
int arr[] = {123,12348,12,45,61,5,49,152,465,16,5489,4,153,12,464,654,8};
int length = sizeof(arr)/sizeof(int);
quicksort(arr, 0, length-1);
for(int i=0;i<length-1;i++){
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
2.获取基准数位置+双区间合成简化步骤
代码如下(示例):
#include <stdio.h>
#include <algorithm>
/*
快速排序
选第一个为基准数,不断挖坑,
1.从后往前对比,第一个比基准数小的移到low位置
2.从前往后对比,第一个比基准数大的移到上面那个的位置
3.重复2、3操作,直至low==high或low>high
4.再对其它区间进行同样操作
*/
void quicksort(int arr[], int i, int j)
{
//边界判定
if( i >= j )return;
//挖坑(获取基准数),第一个放入的位置。如果在第一个数挖坑,就要从后面开始补坑
int key = arr[i];
int left = i, right = j;
while(i < j)
{
//注意边界判定,不要越界访问
while(i < j && arr[j] >= key)
j--;
if(arr[j] < key)
arr[i] = arr[j];
while(i < j && arr[i] < key)
i++;
if(arr[i] > key)
arr[j] = arr[i];
}
//记得放回key
arr[i] = key;
//对基准数左右两个区间再各自再进行快速排序
quicksort(arr, i+1, right);
quicksort(arr, left, i-1);
return;
}
int main()
{
int arr[] = {123,12348,12,45,61,5,49,152,465,16,5489,4,153,12,464,654,8};
int length = sizeof(arr)/sizeof(int);
//进行快速排序
quicksort(arr, 0, length-1);
//输出排序结果
for(int i=0;i<length-1;i++){
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}