void qsort(vector<int>& vec, int low, int high) {
if (low > high) return;
int slow = low, pivot = vec[low];
// 要对**除了主元的所有元素**进行划分,因此循环的边界很好理解
for (int fast = low+1; fast <= high; ++fast)
if (vec[fast] <= pivot) { // <= 或 < 都是对的~
slow++;
swap(vec[slow], vec[fast]);
}
swap(vec[low], vec[slow]); // 划分完成后再将主元放到其最终位置
qsort(vec, low, slow-1); // vec[slow](即主元)不需要参与排序,
qsort(vec, slow+1, high); // 因为它已经处于正确位置
}
思路就是,每次划分(将数组小于等于pivot和大于pivot的元素分开)的时候,用一个慢指针和一个快指针。每当快指针扫描到小于等于pivot的元素,就将这个元素丢到慢指针的位置(同时慢指针增加)。慢指针指向的元素以及其左边的元素,全都是被快指针丢过来的(也就是小于等于pivot的)。
之所以叫“慢”指针,是因为这个指针只有在快指针发现【小于等于pivot的元素】的时候才会增加,走得比快指针慢。
可以想象到,快指针扫描过程中的任何时刻,慢指针指向、以及其左边的元素都是小于等于pivot的,慢指针与快指针之间的元素都是大于pivot的。
思路来自 https://www.geeksforgeeks.org...
在geeksforgeeks可以测试其正确性。提交代码:
#include <iostream>
#include <vector>
using namespace std;
void swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
void qsort(vector<int>& vec, int low, int high) {
if (low > high) return;
int slow = low, pivot = vec[low];
for (int fast = low+1; fast <= high; ++fast)
if (vec[fast] <= pivot) {
slow++;
swap(vec[slow], vec[fast]);
}
swap(vec[low], vec[slow]);
qsort(vec, low, slow-1);
qsort(vec, slow+1, high);
}
void test() {
int size;
cin >> size;
vector<int> vec(size);
for (int i = 0; i < size; ++i) {
cin >> vec[i];
}
qsort(vec, 0, size-1);
for (int i = 0; i < size; ++i) {
cout << vec[i] << ' ';
}
cout << endl;
return;
}
int main() {
int testNum;
cin >> testNum;
while (testNum--) {
test();
}
return 0;
}
其实这个算法不一定要选择第一个元素作为主元。如果你想选择第i个元素作为pivot,先将第i个元素与第一个元素交换一下,后面不就和刚才的算法一样了吗~
最坏情况:和其他快排一样,每次选择pivot的时候都恰好选到了最大或最小的那个,对size为n的数组进行划分,得到的却是n-1的数组,因此要进行n次划分。因此这种情况下,时间复杂度为n+(n-1)+(n-2)+....+0,也就是O(n^2)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。