前言
前几天美团面试官问了快速排序
要当场实现,其实思路有了,本身也很简单,但是奈何已经很久没有实现了,所以全程细节实现起来很磕绊
事后总结一下,规范为标准代码,以后可以直接拿来就用
事先说明(可以跳过直接看代码)
网络上的资源很多很杂,拿来代码就会发现很多细节问题真的很容易搞混
所以我这里采用了
经典算法书的代码
虽然书中用的是Java,但是没有特别难懂的,所以就沿用了代码,以及用C++实现
Java代码是这样的(沿用了教学PPT)
快速排序
时间复杂度O(nlogn)(最坏情况,全部为重复元素的数组 时间复杂度O(n^2))
空间复杂度O(logn)(最坏情况,全部为重复元素的数组 空间复杂度O(n))
函数
- Partition(int* arr (待排序数组arr),int left(待排序数组最左值下标),int right(待排序数组最右值下标));
- 功能:分类思想;小于哨兵元素放左边,大于的放右边;
- 返回值类型int : 返回 每进行完一次排序(即排序后哨兵左边都是小于其的数字,右边都是大于其的数字)过后哨兵值(此时在中间)所在的下标;
- Quicksort(参数与上同);
- 功能:递归调用自身;将哨兵左右两边的数组分别排序;
- 返回值类型void (调用直接返回有序数组);
- swap(&a,&b);
- 功能:标准的交换两个数字的函数;
- 返回值类型void (调用之后交换左右值)。
#include<iostream>
using namespace std;
int partition(int* arr,int left,int right){
int i = left;
int j = right + 1;//对应--j
int pivot = arr[left];//哨兵
while(true)
{
while(arr[++i] <= pivot) //跳过第一个值
if(i == right) break;
while(arr[--j] >= pivot)//j--会多跳;保证j当前所在元素符合判断条件
if(j == left) break;
if(i >= j) break;//左右指针相遇或交叉就退出
swap(arr[i], arr[j]);
}
swap(arr[left], arr[j]);
return j;
}
void swap(int &a,int &b){
int tmp = a;
a = b;
b = tmp;
}
void Quicksort(int* arr, int left, int right)
{
if(left >= right)//终止判断条件
return;
int j = partition(arr, left, right);
Quicksort(arr, left, j-1);
Quicksort(arr, j+1, right);
}
int main(){
int n;
cin >> n;
int arr[n+2];
for(int i = 0 ; i < n ; i++)
cin>>arr[i];
Quicksort(arr, 0, n-1);
for(int i = 0 ; i < n ; i++)
cout<<arr[i]<<" ";
return 0;
}
输入说明
第一行输入数字n:代表即将输入的整形数组长度;
第二行输入数组元素:arr[n];
输出说明
输出排序好的数组arr,即n个整形数字
注意点
- Partition函数中i、j分别为左右“指针”(类似指针的功能),初始为最左以及最右数字+1的原因:函数内循环条件++i/--j,即保证了每次循环结束时 i / j所指在位置的值满足括号中的判断条件以及最终循环结束时不会发生越界;
- Partition函数中 swap函数出现了两次,分别的作用是:
- 1.交换i j未相遇前,i下标所在元素的值大于哨兵元素的值,j下标所在元素的值小于哨兵元素的值;
- 2.内层循环完后,交换 哨兵元素 与 j下标所在元素,使得哨兵元素在中间,方便后续Quicksort()函数递归操作;
- Quicksort函数因为有递归操作,所以必须严格说明递归终止条件:
- if(left >= right)//终止判断条件
return;
- swap函数的引用就不用再多说了,指针也可以实现。