歸併排序使用多線程分析
歸併排序分爲兩步:
- 不斷地對半拆分數組(向下的過程);
- 合併相鄰的子數組(向上的過程)。
對於拆分成的子數組,它們之間相互獨立,資源不共享,因此用多線程是安全的。(在合併前,兩個子線程需要運行完畢,即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;
}