归并排序是一种利用合并排序而完成排序的算法(牺牲了空间复杂度来换取时间复杂度)
基本的排序思路如下:
首先将有待排序的区间中每个元素看做是一个有序表如果数组大小为n则(看做n个有序表)通过两两合形成n/2张有序表,这个过程也叫做一趟合并。
然后接着将剩下的n/2张有序表进行两两合并生成n/2*2个长度为4的有序表如此循环直到得到一个长度为n的有序表,通常需lon2 n 趟,如果该
值为奇数则为log 2 n + 1.
我做一个比较直观的展示吧
假设是这样一组数:23 45 12 56 22 50 78 32
第一步:【23 45】【12 56】【22 50】【32 78】// 合并之前上一步中是经过排序的 括号内都是有序表
第二步:【12 23 45 56】【22 32 50 78】
第三步:【12 22 23 32 45 50 56 78】
那么这是思路而已如果你真以为那么简单,我只想说你太天真了。你以为这么好能混饭吃?接着往下才是重点,我自己完全搞明白也花了点时间,好好看下面的,在实际中我们编程是这样实现的:利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,1划分子表 2合并半子表
1 // 归并排序.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 using namespace std; 7 8 //将有二个有序数列a[first...mid]和a[mid...last]合并。 9 template <typename T> 10 void mergearray(T a[], int first, int mid, int last, T temp[]) 11 12 { 13 int i = first, j = mid + 1; 14 int m = mid, n = last; 15 int k = 0; 16 while (i <= m && j <= n) //比较两个序列中比较小的存放在合并temp之中 并移动指针到下一个位置 17 { 18 if (a[i] <= a[j]) 19 temp[k++] = a[i++]; 20 else 21 temp[k++] = a[j++]; 22 } 23 24 25 while (i <= m) //复制没有比较完子表中的元素 ,左边有剩余则直接拷贝到temp之后 26 temp[k++] = a[i++]; 27 28 while (j <= n) //右边有剩余直接拷贝到temp后面 29 temp[k++] = a[j++]; 30 31 for (i = 0; i < k; i++) //排序完成之后的数组拷贝到temp之中 32 a[first + i] = temp[i]; 33 } 34 35 template <typename T> 36 void mergesort(T a[], int first, int last, T temp[]) 37 { 38 if (first < last) // 这句话的实际意义就相当于一个递归终止flag 39 { 40 int mid = (first + last) / 2; 41 42 mergesort(a, first, mid, temp); //左边有序 43 44 mergesort(a, mid + 1, last, temp); //右边有序 45 46 mergearray(a, first, mid, last, temp); //再将二个有序数列合并 47 } 48 } 49 50 template <typename T> 51 bool mergesort(T a[], int n) 52 { 53 T *p = new T[n]; 54 if (p == NULL) 55 return false; 56 57 mergesort(a, 0, n - 1, p); 58 59 delete[] p; 60 61 return true; 62 63 } 64 int main(int argc, char* argv[]) 65 { 66 int i = 0; 67 int Num[10] = {0,2,5,6,77,8,1,98,4,3}; 68 cout<<"原数组:"<<endl; 69 while ( i < 10) 70 { 71 cout<<Num[i]; 72 i++; 73 cout<<" "; 74 } 75 cout<<endl; 76 i = 0; 77 mergesort(Num,sizeof(Num)/sizeof(int)); 78 cout<<"归并排序后:"<<endl; 79 80 while ( i < 10) 81 { 82 cout<<Num[i]; 83 i++; 84 cout<<" "; 85 } 86 cout<<endl; 87 return 0; 88 }
即使我把代码注释的如此详细我依然坚信你看不懂 为什么呢?因为你的递归没学好~~!!是不?这个归并排序其实用到了递归的思想,
void mergesort(T a[], int first, int last, T temp[]) { if (first < last) // 这句话的实际意义就相当于一个递归终止flag { int mid = (first + last) / 2; mergesort(a, first, mid, temp); //左边有序 mergesort(a, mid + 1, last, temp); //右边有序 mergearray(a, first, mid, last, temp); //再将二个有序数列合并 } }
这一段代码就是利用了递归 将数组一分为2,注意判断里面first<last 不然的话意味着我们已经分到中间 分完了 这样也就不必再递归了 一层一层分为两部分,其实用语言我很难跟你解释清楚,最好的办法是你自己能够通过调试的方法去感受。
我们做递归必须明白我们重复的过程是什么 以及终止的条件是什么,过程就是左右两边不断有序和层层分治。一旦有序和切割完成我们就要对齐进行再次的组合。也就是最后一个合并的函数mergearray;假如你真的很难理解的话,你按照我所说的去想象,mergesort函数将一列数组一分为二,但是first<last意味着他们中间还有元素,那就接下来递归就来了继续做那个函数继续一分为二,知道first>=last意味着分到了两个两个一组,这样进行完成之后再按照递归层层合并~~直至最后还原原来的大小但是排序已经完成。