首先先讲讲分治思想。分治即将原问题分解为几个规模较小但类似于原问题的子问题,递归求解这些子问题,然后再合并这些子问题的解来建立问题的解。(《算法导论》中的原话)
知道了分治,那么该如何实现呢。根据上面的描述,我们要解决的几个主要的问题是:
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; }