排序算法的c++实现——归并排序

    归并排序是典型分治思想的代表——首先把原问题分解为两个或多个子问题,然后求解子问题的解,最后使用子问题的解来构造出原问题的解。

    对于归并排序,给定一个待排序的数组,首先把该数组划分为两个子数组,然后对子数组进行排序(递归调用归并排序),最后对两个有序的子数组进行合并,使合并之后的数组为有序状态。

    让我们想想,把一个数组不断地划分为子数组,不断地划分......,不断地划分......., 最后停止了划分不下去了。 此时子数组的元素有一个,它们本身就是有序的。接下来,我们就需要执行合并过程,不断地一层层向上合并,........,  直到原数组。通过这个过程就会发现, 归并排序的核心在于合并有序的子数组,而不是对子数组进行排序,因为最底层的子数组本身就是有序的,上一层子数组如果想要变成有序的,通过合并底层有序的子数组就可以得到, 最终我们使原数组变成了有序的,从而完成了排序操作。

 

说明几点:

1. 归并排序采用了分治思想,它的核心在于合并子问题的解而不是求解子问题(快速排序也采用了分治思想,但它的核心是在于求解子问题而不需要合并子问题的解)、

2. 归并排序不是原址排序,它有排序过程中需要借助额外的内存空间。

3. 归并排序为稳定排序(其实呢,具体还得看你怎么写代码,如果两个数的值相等时,你不保持原顺序都就会变成非稳定的了)

4. 归并排序的时间复杂度为O(NlogN).

 

具体代码如下:

  1   /***********************************************************************
  2   *   Copyright (C) 2019  Yinheyi. <chinayinheyi@163.com>
  3   *   
  4   * This program is free software; you can redistribute it and/or modify it under the terms
  5   * of the GNU General Public License as published by the Free Software Foundation; either 
  6   * version 2 of the License, or (at your option) any later version.
  7   
  8   *   Brief:    
  9   *   Author: yinheyi
 10   *   Email: chinayinheyi@163.com
 11   *   Version: 1.0
 12   *   Created Time: 2019年05月06日 星期一 22时22分57秒
 13   *   Modifed Time: 2019年05月09日 星期四 21时10分59秒
 14   *   Blog: http://www.cnblogs.com/yinheyi
 15   *   Github: https://github.com/yinheyi
 16   *   
 17   ***********************************************************************/
 18   
 19   
 20   // 归并排序,分治法的典型代表: 将原问题分解了几个子问题,解决子问题,再合并子问题的解,
 21   // 这样就得到了原问题的解。
 22   // 分治本质上就是把原问题分解为几个子问题来解决。
 23   // 快速排序也是分治思想来解决。
 24   //
 25   //
 26   // 归并排序(merge-sort):
 27   // 1. 把一个待排序的数组分解为两个子数组;
 28   // 2. 对两个子数组进行排序(通过递归地调用自己来实现);
 29   // 3. 对两个已经排序的数组进行合并。
 30   //
 31   // 分析:
 32   // 1. 一个数组一直分解下去,只到分解成只包含一个元素的子数组为止, 此时自然是有序的;
 33   // 2. 归并排序的重点在于合并,而不是对子数组的排序。(快速排序与它恰恰相反,快速排序的
 34   // 重点是对子数组进行排序,而不是合并,因为它不需要合并了)
 35   //
 36   //
 37   #include <cstring>
 38   #include <iostream>
 39   typedef bool(*CompareFunc)(int, int);
 40   
 41   // 下面函数实现合并功能,输入三个下标参数表示了两个子数组, :[nStart_, nMiddle)和[nMiddle, nEnd)
 42   void Merge(int array[], int nStart_, int nMiddle_, int nEnd_, CompareFunc comp)
 43   {   
 44       if (array == nullptr || nStart_ >= nMiddle_ || nMiddle_ >= nEnd_)
 45           return;
 46       
 47       // 建立一个临时数组存放中间数据
 48       int _nIndex = 0; 
 49       int* _pTempArray = new int[nEnd_ - nStart_];
 50       
 51       // 对两个子数组进行合并
 52       int _nStartChange = nStart_;
 53       int _nMiddleChange = nMiddle_;
 54       while (_nStartChange < nMiddle_ && _nMiddleChange < nEnd_)
 55       {
 56           // 此处的if中比较语句的安排可以保持稳定排序的特性。
 57           if (comp(array[_nMiddleChange],  array[_nStartChange]))
 58           {
 59               _pTempArray[_nIndex] = array[_nMiddleChange];
 60               ++_nMiddleChange;
 61           }
 62           else
 63           {
 64               _pTempArray[_nIndex] = array[_nStartChange];
 65               ++_nStartChange;
 66           }
 67           ++_nIndex;
 68       }
 69       
 70       // 把不为空的子数组的元素追加到临时数
 71       if (_nStartChange < nMiddle_)
 72       {
 73           memcpy(_pTempArray + _nIndex, array + _nStartChange, sizeof(int) * (nMiddle_ - _nStartChange));
 74       }
 75       else if (_nMiddleChange < nEnd_)
 76       {
 77           memcpy(_pTempArray + _nIndex, array + _nMiddleChange, sizeof(int) * (nEnd_ - _nMiddleChange));
 78       }
 79       else
 80       {
 81           /* do noting */
 82       }
 83   
 84       // 数据交换
 85       memcpy(array + nStart_, _pTempArray, sizeof(int) * (nEnd_ - nStart_));
 86   
 87       delete [] _pTempArray;
 88       _pTempArray = nullptr;
 89   }
 90   
 91   // 归并排序功能实现函数
 92   void MergeSort(int array[], int nStart_, int nEnd_, CompareFunc comp)
 93   {
 94       // 数组指针为空,或者数组内的个数少于等于1个时,直接返回。
 95       if (nullptr == array ||  (nEnd_ - nStart_) <= 1)
 96           return;
 97   
 98       // 划分为两个子数组并递归调用自身进行排序
 99       int _nMiddle = (nStart_ + nEnd_) / 2;
100       MergeSort(array, nStart_, _nMiddle, comp);
101       MergeSort(array, _nMiddle, nEnd_, comp);
102   
103       // 合并排序完成的子数组
104       Merge(array, nStart_, _nMiddle, nEnd_, comp);
105   }
106   
107   // 比较函数
108   bool less(int lhs, int rhs)
109   {
110       return lhs < rhs;
111   }
112   
113   // 打印数组函数
114   void PrintArray(int array[], int nLength_)
115   {
116       if (nullptr == array || nLength_ <= 0)
117           return;
118   
119       for (int i = 0; i < nLength_; ++i)
120       {
121           std::cout << array[i] << " ";
122       }
123   
124       std::cout << std::endl;
125   }
126   
127   /***************    main.c     *********************/
128 >>int main(int argc, char* argv[])
129   {
130       // 测试1
131       int array[10] = {1, -1, 1, 231321, -12321, -1, -1, 123, -213, -13};
132       PrintArray(array, 10);
133       MergeSort(array, 0, 10, less);
134       PrintArray(array, 10);
135   
136       // 测试2
137       int array2[1] = {1};
138       PrintArray(array2, 1);
139       MergeSort(array2, 0, 1, less);
140       PrintArray(array2, 1);
141   
142       // 测试3
143       int array3[2] = {1, -1};
144       PrintArray(array3, 2);
145       MergeSort(array3, 0, 2, less);
146       PrintArray(array3, 2);
147   
148       return 0;
149   }

 

posted @ 2019-05-09 21:16  殷大侠  阅读(17034)  评论(0编辑  收藏  举报