思路来自 https://www.geeksforgeeks.org...ios
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); }
思路就是,每次划分(将数组小于等于pivot和大于pivot的元素分开)的时候,用一个慢指针和一个快指针。每当快指针扫描到小于等于pivot的元素,就将这个元素丢到慢指针的位置(同时慢指针增长)。慢指针指向的元素以及其左边的元素,全都是被快指针丢过来的(也就是小于等于pivot的)。c++
之因此叫“慢”指针,是由于这个指针只有在快指针发现 【小于等于pivot的元素】的时候才会增长,走得比快指针慢。
能够想象到,快指针扫描过程当中的任什么时候刻,慢指针指向、以及其左边的元素都是小于等于pivot的,慢指针与快指针之间的元素都是大于pivot的。算法
在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)。ui