數據結構與算法 —— O(nlogn)排序算法(希爾和快排)(c++)

希爾排序

https://blog.csdn.net/u012918361/article/details/68921601
希爾排序作爲第一批突破O(n^2)的算法之一,在數據中等規模時候性能很好,大規模時候沒有快排好
時間複雜度O(nlogn)不好證明
基本思路:插入排序的改進,就是不斷分組,每組進行插入排序

注意傳入引用,不然按值傳遞速度很慢

void ShellSort(vector<int>& v)
{
    int length = v.size();
    for (int gap = length / 2; gap > 0; gap = gap / 2)  // d,分的組數,比如數組長度14,則分爲7,3,1
    {
        //插入排序
        for (int i = gap; i < length; i++)  // i遍歷每組中未排序元素
        {
            int temp = v[i];
            int j = 0;
            for (j = i - gap; j >= 0; j -= gap)  // j遍歷已排序數組(從後往前),把i插入到適當位置
            {
                if (temp < v[j]) {
                    v[j + gap] = v[j];  //後移
                } else {
                    break;
                }
            }
            v[j + gap] = temp;
        }
    }
}

快速排序(分治+挖坑法)

https://cloud.tencent.com/developer/article/1338521
https://www.cxyxiaowu.com/5262.html
先後策略來把一個序列分爲較小和較大的2個子序列,然後遞歸地排序兩個子序列。
分治思想
1.挑選基準值 2.分割:所有比基準值小的元素放在基準值前面,大的都放到基準值後面,在這個過程結束後,基準值的排序就完成了。3。遞歸
挖坑思想
分割的時候使用挖坑法:每次取第一個作爲基準值,然後從右向左排坑,再從左向右排坑,每次循環會把一個大數放後面,把一個小的數放前面。完整循環後,會把基準數放到正確的位置。

// 快排分解解析
// partition方法就是把傳入的數組中第一個數作爲基準值,然後把基準值放到正確的位置,返回這個位置
int partition(vector<int>& arr, int l, int r)
{
    int temp = arr[l];  // 基準值
    while (l < r) {
        while (l < r && arr[r] >= temp)
            r--;
        arr[l] = arr[r];
        while (l < r && arr[l] <= temp)
            l++;
        arr[r] = arr[l];
    }
    arr[l] = temp;
    return l;
}
//分治代碼
void quickSort(vector<int>& arr, int low, int high)
{
    if (low >= high)
        return;

    //每次把基準值的位置放正確
    int index = partition(arr, low, high);
    // Separately sort elements before
    // partition and after partition
    quickSort(arr, low, index - 1);   //對基準值左側進行排序
    quickSort(arr, index + 1, high);  // 對基準值右側再排序
}

整理後的簡潔代碼

void QuickSort(vector<int>& s, int l, int r)
{
    //終止條件
    if (l >= r)
        return;
    //每次基準值的放置,使用挖坑法
    int i = l, j = r;  //定義左右兩個指針
    int x = s[l];      //選取第一個數作爲基準值
    while (i < j) {
        // 從右向左找第一個小於基準數的數
        while (i < j && s[j] >= x)
            j--;
        if (i < j) {
            s[i] = s[j];  // 找到該數,放入坑中,
            i++;          //左指針後移一位
        }
        // 從左向右找第一個大於等於基準數的數
        while (i < j && s[i] < x)
            i++;
        if (i < j) {
            s[j] = s[i];
            j--;
        }
        //一次循環後,把一個大於基準數的數放到右邊,一個小於基準數的數放到左邊
    }          //整個循環後,大於基準數的數都放到了右邊,小於key都放到了左邊
    s[i] = x;  // 基準數找到了合適的位置
    //分治,遞歸調用
    QuickSort(s, l, i - 1);  //基準值左邊
    QuickSort(s, i + 1, r);  //基準值右邊
}

測試用例

#include <iostream>
#include <vector>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;
int main()
{
    int N = 1000000;  //一百萬
    // int N = 1000;
    srand(time(NULL));  //生成隨機數種子
    //放到vector中
    vector<int> nums(N);
    for (int i = 0; i < N; ++i) {
        nums[i] = 1 + (rand() % N);
    }
    //開始計時
    double start, finish; 
    start = (double)clock();

    // ShellSort(nums);  // 525ms
    QuickSort(nums, 0, N - 1);  // 180ms
    // quickSort(nums, 0, N - 1);  // 200ms

    finish = (double)clock();

    //打印
    // for (auto item : nums) {
    //     cout << item << ",";
    // }
    cout << endl;
    printf("%.4fms\n", (finish - start));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章