歸併排序之多線程實現(C++)

歸併排序使用多線程分析

歸併排序分爲兩步:

  1. 不斷地對半拆分數組(向下的過程);
  2. 合併相鄰的子數組(向上的過程)。
    對於拆分成的子數組,它們之間相互獨立,資源不共享,因此用多線程是安全的。(在合併前,兩個子線程需要運行完畢,即join阻塞當前線程直到兩個子線程運行完畢)

C++代碼

#include <iostream>
#include <thread>
#include <vector>
#include <functional>

using namespace std;

void merge(vector<int>& nums, int s, int mid, int e){
    vector<int> lnums, rnums; // lnums, rnums爲兩個子序列,nums用於存放合併後的序列
    for(int i = s; i <= e; i++){
        if(i <=mid){
            lnums.push_back(nums[i]);
        }else{
            rnums.push_back(nums[i]);
        }
    }

    int l = 0, r = 0, k = s;
    // 比較兩個指針(l和r)所指向的元素,選擇相對小的元素(升序)放入到合併空間,
    // 並移動指針到下一位置,直到其中一個指針超出序列尾
    while(l < lnums.size() && r < rnums.size()){
        if(lnums[l] < rnums[r]){
            nums[k++] = lnums[l++];
        }else{
            nums[k++] = rnums[r++];
        }
    }
    // 將另一序列剩下的所有元素直接複製到合併序列尾
    while(l < lnums.size()){
        nums[k++] = lnums[l++];
    }
    while(r < rnums.size()){
        nums[k++] = rnums[r++];
    }
}

void mergeSort(vector<int>& nums, int s, int e){
    if(s >= e){
        return;
    }

    int mid = (s + e)/2;
    // 向下拆分,獨立進行,可以多線程
    // 疑問:爲什麼要用bind(),thread t1(mergeSort,std::ref(nums),s,mid);編譯錯誤?
    // std::bind默認採用參數的拷貝而不是引用,用std::ref轉化爲引用
    thread t1(std::bind(mergeSort,std::ref(nums),s,mid));
    thread t2(std::bind(mergeSort,std::ref(nums),mid+1,e));
    t1.join();
    t2.join();
    // mergeSort(nums,s,mid);
    // mergeSort(nums,mid+1,e);
    // 向上合併
    merge(nums,s,mid,e);
}

vector<int> sortArray(vector<int>& nums) {
    // 歸併排序
    vector<int> arr = nums; // 爲了不改變原數組
    mergeSort(arr,0,arr.size()-1);
    return arr;
}

int main(){
    vector<int> nums{10,9,8,7,2,3,4,5,6,1,0}, re;
    re = sortArray(nums);
    for(int num:re){
        cout << num << " ";
    }
    cout << endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章