本文系转载,出处:https://segmentfault.com/a/1190000002651247
今天看到 V2EX 上有人讨论 社招还会问 “请手写选择排序算法” 吗,看来还是有很多人关心的。结合自己最近面试的经历,我可以明确的告诉大家,类似这种问题,只要你的工作经验小于 10 年,基本上逃不掉。劝大家不如抽点时间早做准备。
面试中遇到问快排的,如上面那个帖子中的情况。你就可以上一份简式快排了,何谓简式?最短的代码表述快排的思想。
快速排序算法用白话说,就是从头到尾迭代,和支点比较,大的不管,小的换。换了才往后看。最后支点戳中间,算是分界线。
快排的思想,实质是分治法。基于什么来分?找一个支点来分,通常称之为 pivot
, 而这个分的过程称之为 partition
, 基于以上两点,我们用递归的方式描述快排:
void quicksort(vector<int> &vi, int l, int r) {
if (l < r) {
int pivot = partition(vi, l, r);
quicksort(vi, l, pivot-1);
quicksort(vi, pivot+1, r);
}
}
如何?简单吧。有人说面试的时候手写快排,如果提前没有背下来的话,肯定歇菜。我不认为这样基础的算法是需要背的,上面这个递归,如此简洁,如此美,真的需要硬记?
有人说,这个好理解,关键在于 partition
如何实现。的确,partition
是快排的灵魂。CLRS
里采用了以尾巴为支点的策略,我在这里与其保持一致:
int partition(vector<int> &vi, int l, int r) {
int k = l, pivot = vi[r];
for (int i = l; i < r; ++i)
if (vi[i] <= pivot) swap(vi[i], vi[k++]);
swap(vi[k], vi[r]);
return k;
}
完整代码整理:
#include <iostream>
#include <vector>
using namespace std;
int partition(vector<int> &vi, int l, int r) {
int k = l, pivot = vi[r];
for (int i = l; i < r; ++i)
if (vi[i] <= pivot) swap(vi[i], vi[k++]);
swap(vi[k], vi[r]);
return k;
}
void quicksort(vector<int> &vi, int l, int r) {
if (l < r) {
int pivot = partition(vi, l, r);
quicksort(vi, l, pivot-1);
quicksort(vi, pivot+1, r);
}
}
int main()
{
int a[] = {3,5,7,9,2,3,1,0,7,5,4};
vector<int> va(a, a+11);//array转vector
cout<<"Before quicksort:\n";
for(int x:va)
cout<<x<<" ";
cout<<endl;
cout<<"After quicksort:\n";
quicksort(va, 0, va.size() - 1);
for(int x:va)
cout<<x<<" ";
return 0;
}