【C++】歸併排序

性能分析:

  時間複雜度:O(n*log(n))

  空間複雜度:O(n)

歸併排序演算法來自於分而治之思想,「歸」是「遞歸」的意思,「並」是”合併「的意思,就是說將複雜的數組排序問題先進性分解,然後遞歸的解決小問題,最後合併問題的解。

#include<iostream>
#include<vector>
using namespace std;
void sort_merge_recursive(vector<int>& data, int left, int right);
void merge(vector<int>& data, int left, int mid, int right);

int main()
{
    // 首先找出待排序列中最小的數,然後用這個數和原序列中的第一個數交換位置;
    // 其次,找出第二小的和原第二個數交換位置;
    // 依次順序直到找到第二大的數,之後原數列完全變成有序數列.
    vector<int> data = { 3,0,5,2,7,8,9,6,1 };
    //獲取序列元素個數
    int length = 9;
    int left = 0;
    int right = 8;
    sort_merge_recursive(data, left, right);

    for (int i = 0; i < length; i++)
    {
        cout << data[i] << "   ";
    }
}

void sort_merge_recursive(vector<int> &data, int left, int right)
{
    if (left < right)//暗含如果left>=right就不做任何操作,因為這個時候表示已經分解到只剩一個元素了,天然有序
    {
        //將序列一分為二獲取中間位置
        int mid = (left + right) / 2;
        //遞歸處理兩個子序列使之有序
        sort_merge_recursive(data, left, mid);
        sort_merge_recursive(data, mid + 1, right);
        //合併兩個有序子序列
        merge(data, left, mid, right);
    }
}

void merge(vector<int> &data, int left, int mid, int right)
{
    //將有序的兩個子序列合併起來
    //獲取兩個子序列的第一個元素
    int i = left;
    int j = mid + 1;
    //創建臨時容器來保存合併結果,同時指定容器大小
    vector<int> temp;
    temp.resize(right - left + 1);//從圖中最底下開始往上合併,每一次因為要合併兩個子序列,所以容器大小要從新設置
    //開始合併
    int k = 0;//臨時容器的索引
    while (i <= mid && j <= right)
    {
        if (data.at(i) <= data.at(j))//如果左邊的值元素值小於右邊的
        {
            temp.at(k++) = data.at(i++);//先把小的放到數組前面
        }
        else
        {
            temp.at(k++) = data.at(j++);
        }
    }
    //到這裡肯定已經有一個子序列的所有元素已經完全放到了容器里,接著放另一個剩下的元素
    while (i <= mid)//因為不知道是哪個完全放進去了,用這種方式來判斷
    {
        temp.at(k++) = data.at(i++);
    }
    while (j <= right)
    {
        temp.at(k++) = data.at(j++);
    }

    //只能通過這樣的方式將臨時容器元素複製給原始容器得到結果
    for (int n = 0; n < k; n++)
    {
        data.at(left++) = temp.at(n);
    }
}