首先先講講分治思想。分治即將原問題分解爲幾個規模較小但類似於原問題的子問題,遞歸求解這些子問題,然後再合併這些子問題的解來建立問題的解。(《算法導論》中的原話)
知道了分治,那麼該如何實現呢。根據上面的描述,我們要解決的幾個主要的問題是:
1.如何分解原問題
2.如何進行遞歸求解。因爲遞歸都要有個盡頭,所以這裏我們還要定義一個最小的子問題。
3.如何合併那些已經解決了的子問題。
代碼:
MergeSort.h
#pragma once class MergeSort { private: int* data; // 數據 int length; // 數據個數 public: MergeSort(int* &d, int size) : data(d), length(size) {} ~MergeSort(void){ if(data != nullptr) { delete data; data = nullptr; } } void output() const; void sort(); void swap(int i, int j); private: void mergeSort(int p, int q); void merge(int p, int q, int r); };
MergeSort.cpp#include "MergeSort.h" #include <iostream> void MergeSort::output() const { int i = 0; while(i < length) { std::cout<<data[i]<<" "; i++; } std::cout<<"\n"; } void MergeSort::sort() { mergeSort(0, length); } /* * 分解原問題,將數組分爲左部分和右部分。那麼我們要分割的最小情況是,左邊爲 * 只有一個元素的數組,右邊也是隻有一個元素的數組。 * @param p 爲左邊的起始索引,包含p * @param r 爲右邊的終止索引,不包含r */ void MergeSort::mergeSort(int p, int r) { if(r - p >= 2) { std::cout<<p<<":"<<r<<std::endl; int q = (p + r) / 2; // 取中點 mergeSort(p, q); // 對左邊進行遞歸 mergeSort(q, r); // 對右邊進行遞歸 merge(p, q, r); // 合併左右兩邊,則p,r之間的元素已排序好 } } /* * 寫代碼的時候在意細節也許是好事。比如,我在寫的時候喜歡帶入數字計算q-p是不是 * 就算出正確的數組元素個數。但是這樣即使自己帶入的數字能計算出正確的結果,這也 * 只是讓自己暫時安心。 * 當疑惑時,應該先明確自己定的每個參數表達的意義,然後再去驗證,這樣作可以加深 * 自己對代碼的理解。事倍功半。 */ void MergeSort::merge(int p, int q, int r) { int n1 = q - p; // 左邊數組元素的個數 int n2 = r - q; // 右邊數組元素的個數 int* lArr = new int[n1 + 1]; // +1個元素是爲了在數組的末尾增加一個哨兵 int* rArr = new int[n2 + 1]; for(int i = 0; i < n1; i++) { lArr[i] = data[p + i]; } for(int j = 0; j < n2; j++) { rArr[j] = data[q + j]; } lArr[n1] = RAND_MAX; // 哨兵來了 rArr[n2] = RAND_MAX; int lIndex = 0, rIndex = 0; for(int k = p; k < r; k++) { if(lArr[lIndex] <= rArr[rIndex]) // 有了哨兵,比較的時候就不用擔心數組越界 { // 同時簡化了代碼 data[k] = lArr[lIndex]; lIndex++; } else { data[k] = rArr[rIndex]; rIndex++; } } } // 數值交換方法,只對整型數據有效 void MergeSort::swap(int i, int j) { data[i] ^= data[j]; data[j] ^= data[i]; data[i] ^= data[j]; }
Main.cpp#include <iostream> #include <time.h> #include "MergeSort.h" // 獲取[1,500]範圍內的隨機數 int proRandNum() { return rand() % 500 + 1; } int main() { using namespace std; srand((unsigned)time(NULL)); // 設置隨機數種子 int size = 20; int *data = new int[size]; for(int i = 0; i < size; i++) { data[i] = proRandNum(); } MergeSort* sort = new MergeSort(data, size); cout<<"before sorted:\n"; sort->output(); cout<<"after sorted:\n"; sort->sort(); sort->output(); system("pause"); return 0; }