思路
- 分治思想。
- 以数组第一个元素作为base(arr[left]),end从右边开始往左边找,当找到一个比base小的元素的时候,end位置停下来;begin从左往右找,当找到一个比base大的元素的时候,begin位置停下来;此时对调end位置和begin位置的元素;如此循环,当begin不满足小于end的时候,停止做上面的动作。
- 对调arr[left]和arr[begin],对调后,此时所有比arr[begin](就是之前的base)小的元素都在它的左侧,比arr[begin]大的元素都在它右侧。
- 再分别对begin位置左边和右边的两个子数组做上面同样的动作,递归(直到子数组为空或只有一个元素位置)。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void quickSort(vector<int>& arr, int left, int right)
{
if(arr.empty() or left >= right)
{
return;
}
int begin = left;
int end = right;
while(begin < end)
{
while(arr[end] >= arr[left] and begin < end) //从大到小则while(arr[end] <= arr[left] and begin < end)
{
--end;
}
while(arr[begin] <= arr[left] and begin < end) //从大到小则while(arr[begin] >= arr[left] and begin < end)
{
++begin;
}
if(begin < end)
{
swap(arr[begin], arr[end]);
}
}
//基准数归位
swap(arr[left], arr[begin]);
quickSort(arr, left, begin - 1);
quickSort(arr, begin + 1, right);
}
测试
int main()
{
vector<int> va = {3,2,1,5,4,6,8,7,9,10};
quickSort(va, 0, va.size()-1);
for(const auto& item : va)
{
cout << item << " ";
}
cout << endl;
return 0;
}
PS F:\HW> g++ .\QuickSort.cpp -o QuickSort.exe
PS F:\HW> .\QuickSort.exe
1 2 3 4 5 6 7 8 9 10
PS F:\HW> g++ .\QuickSort.cpp -o QuickSort.exe
PS F:\HW> .\QuickSort.exe
10 9 8 7 6 5 4 3 2 1
重构
int partition(vector<int>& arr, int left, int right)
{
int begin = left;
int end = right;
while(begin < end)
{
while(arr[end] >= arr[left] and begin < end)
{
--end;
}
while(arr[begin] <= arr[left] and begin < end)
{
++begin;
}
if(begin < end)
{
swap(arr[begin], arr[end]);
}
}
swap(arr[left], arr[begin]);
return begin;
}
void quickSort(vector<int>& arr, int left, int right)
{
if(left < right)
{
int anchor = partition(arr, left, right);
quickSort(arr, left, anchor - 1);
quickSort(arr, anchor + 1, right);
}
}
- ACM算法日常给出的partition
首先是设定锚点,使用区间最右边的值作为锚点,然后遍历区间每一个数x,如果x小于锚点,就将x与左边的哨兵进行交换,因为x的位置肯定大于等于哨兵位置,所以交换不会产生副作用。最后将锚点交换到哨兵的下一个位置,完成分区任务。
一句话记忆:将小于锚点的数放到左边
int partition2(vector<int>& arr, int low, int high)
{
int anchor = arr[high];
int i = low;
for (int j = low; j <= high - 1; j++) {
if (arr[j] <= anchor) {
// 永恒经典,一次遍历搞定绕着锚点分大小
swap(arr[i++], arr[j]);
}
}
// 最后把锚点放到中间来
swap(arr[i], arr[high]);
//返回锚点的位置
return i;
}
参考
https://mp.weixin.qq.com/s/nj3K65VMJq1I6TP_NXIixg