zoukankan      html  css  js  c++  java
  • 排序算法的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   }
  • 相关阅读:
    CF938E Max History
    经典论文系列 | 目标检测--CornerNet & 又名 anchor boxes的缺陷
    在 Intenseye,为什么我们选择 Linkerd2 作为 Service Mesh 工具(Part.2)
    在 Intenseye,为什么我们选择 Linkerd2 作为 Service Mesh 工具(Part.1)
    Java概述
    算法 --- 二分法 冒泡排序 递归 快速排序
    二维数组
    数组
    SNMP "Simple Network Management Protocol" "简单网络管理协议"。
    常用api --- BigDecimal 包装类 Integer Arrays
  • 原文地址:https://www.cnblogs.com/yinheyi/p/10840465.html
Copyright © 2011-2022 走看看