算法:一個好理解、不用記憶邊界狀況的快排(10行)

思路來自 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

相關文章
相關標籤/搜索