歸併排序是分治法(Divide-and-Conquer)的典型應用:
Divide the problem into a number of subproblems.
Conquer the subproblems by solving them recursively. if the subproblem sizes are small enough, just sovle the subproblems in a straightforward manner.
Combine the solutions to the subproblems into the solution for the original problem.
對于歸並排序,需要考量的是:
遞:將待排序數組劃分為左邊和右邊,並對於左邊和右邊進行遞迴地排序。直到左邊和右邊只剩下一個元素——直接求解。
歸:遞迴合并結果得到最終解。
代碼:
#include "stdafx.h"#define MAX 99999;#define SIZE 7void PrintNewLine();void PrintArray(int arr[]);void MergeSort(int arr[], int p, int r);void Merge(int arr[], int p, int q, int r);int _tmain(int argc, _TCHAR* argv[]){int original[] = {6,4,3,1,7,5,2};PrintArray(original);PrintNewLine();MergeSort(original,0,SIZE - 1);PrintArray(original);PrintNewLine();char wait = getchar();return 0;}void MergeSort(int arr[], int p, int r){if( r > p ){//divide&conqurer by recursionint q = (p + r) / 2;MergeSort(arr, p, q);MergeSort(arr, q+1, r);//combineMerge(arr, p, q, r);printf("Merge(%d,%d,%d) => ",p,q,r);PrintArray(arr);PrintNewLine();}}void Merge(int arr[], int p, int q, int r){//calc left side and right sideint nLeft = (q - p) + 1;int nRight = r - q;int* leftArr = new int[nLeft];int* rightArr = new int[nRight];//copy element to left&right sidefor(int i = 0; i < nLeft; i++){leftArr[i]=arr[p+i];}for(int j=0; j<nRight; j++){rightArr[j]=arr[(q+j) + 1];}//sentinelleftArr[nLeft] = MAX; rightArr[nRight] = MAX;//pick the small card in original arrayint i = 0, j = 0;for(int k = p; k <= r; k++){if(leftArr[i] < rightArr[j]) //sentinel takes effect{arr[k] = leftArr[i];i++;}else{arr[k] = rightArr[j];j++;}}}void PrintArray(int arr[]){for(int i = 0; i < SIZE; i++)printf("%d ",arr[i]);}void PrintNewLine(){printf("\n");}
輸出:
6 4 3 1 7 5 2Merge(0,0,1) => 4 6 3 1 7 5 2Merge(2,2,3) => 4 6 1 3 7 5 2Merge(0,1,3) => 1 3 4 6 7 5 2Merge(4,4,5) => 1 3 4 6 5 7 2Merge(4,5,6) => 1 3 4 6 2 5 7Merge(0,3,6) => 1 2 3 4 5 6 71 2 3 4 5 6 7
遞迴排序的演算法複雜度為:O(nlgn)。