【fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】

前言

       归并排序是分治法在排序问题上的运用,因此为了更好地了解归并排序,首先了解一下分治法。分治法的基本思想是:将原问题分解为几个规模较小但是类似于原问题的子问题,递归地求解这些子问题,然后合并子问题的解来建立原问题的解。

      分治模式在每层递归时有三个步骤:

      分解原问题为若干子问题,这些子问题是原问题的规模较小的实例;

      解决子问题,递归地求解子问题;若子问题足够小,直接求解;

      合并子问题的解,获得原问题的解。

      归并排序算法遵循分治模式,操作如下:

      分解:分解待排序的具有n个元素的序列,成为具有n/2个元素的两个子序列;

      解决:使用归并排序递归地排序子序列;

      合并:合并已排序的两个子序列产生已排序的答案。

归并排序

在归并排序中,首先将初始序列不断分解,当分解至子序列长度为1时,便开始递归排序。如下图所示,图中初始序列本分解为8个长度为1的子序列,而后开始归并排序;

图 1

在进行排序时,需要一个函数merge()进行操作,在这个函数中有三个下标,分别指向两个子序列中的元素以及归并产生的有序序列中的位置;以上图第二层中的9、11与5、8序列为例,merge()函数执行的操作可以用下图表示。

图 2

在上图中,第一次进行对比后将5放入归并序列中,然后将j与k各往后移动一位。在第二次对比完后,j已经移动到序列尾部,此时只剩下第一个序列中的元素,因为元素已经是有序的,所以直接放入归并序列即可。可以从这一步看出,merge()的时间复杂度为Θ(n)。

编写代码

首先设计一个函数merge_sort()对序列进行二分,当二分至子序列中只含有一个元素时,因为单个元素自身就是“有序”的,无需进行比较;然后将两个具有单个元素的子序列进行归并,这时候就需要调用merge()函数进行归并排序,返回有序的序列。如此往复,直至所有的元素都被排序。思路理清楚了,可以开始写代码;

bool merge_sort(vector<int> &a,int begin,int end)
{//--若只传递了一个参数,无需进行排序,直接返回  if (begin >= end){return true;}int mid = (end + begin) / 2;merge_sort(a, begin, mid);merge_sort(a, mid + 1, end);//--经过上面的归并后两个子序列内部已经是有序的,若两个子序列中第二个子序列的第一个元素已经大于第一个子序列的最后一个元素,则不需要排序;if (a[mid] <= a[mid + 1]){return true;}merge(a, begin, mid, mid + 1, end);return true;
}

merge()函数的功能在上面已经介绍过了,输入参数是主序列以及四个序号,四个序列号分别表示两个子序列的区间。首先创建两个临时序列用于存放子序列,然后开始比较临时序列中的元素,将元素依次存放入主序列当中,实现代码如下;

void merge(vector<int> &a, int l_begin, int l_end,int r_begin,int r_end)
{//if (l_begin == l_end&&r_begin == r_end)     //--如果只有一个元素,则只需比较一次比较了;//{//  if (a[l_begin]>a[r_begin])// {//     int s = a[r_begin];//      a[r_begin] = a[l_begin];//     a[l_begin] = s;        //  }// return ;//}//int leng1 = l_end - l_begin + 1;int leng2 = r_end - r_begin + 1;//--创建两个临时的vector进行存放序列;vector<int> temp_L;vector<int> temp_R;for (int i = 0; i < leng1; i++){temp_L.push_back(a[l_begin+i]);}for (int i = 0; i < leng2; i++){temp_R.push_back(a[r_begin + i]);}int i = 0;int j = 0;while (i < leng1 && j < leng2){if (temp_L[i] <= temp_R[j]){a[l_begin + i + j] = temp_L[i];i++;}else{a[l_begin + i + j] = temp_R[j];j++;}}//--当某个其中一个序列的元素已经全部被放置进入归并后的序列,此时直接将第另一个剩下部分序列放入归并序列即可;while (i <leng1){a[l_begin + i + j] = temp_L[i];i++;}while (j <leng2){a[l_begin + i + j] = temp_R[j];j++;}return ;
}

运行结果

原始序列

排序结果

算法分析

时间复杂度

观察图1可以知道在每一层中每个元素都需要merge()函数进行归并排序,每一层的时间复杂度为Θ(n),而在分解序列时,只需要找到序列的中点,这一步的时间复杂度为Θ(1),为低阶项;进行二分归并时,总共会有层,所以时间复杂度为=,忽略低阶项后,算法的时间复杂度为。(注:分析时间复杂度时常用表示但是在数学中代表)。

空间复杂度

从代码中不难看出,在进行归并时需要一个临时的空间存放序列,所以不是原地排序,排序的空间复杂度为

排序稳定性

归并排序是稳定排序。

完整代码

为了方便大家测试,在这里提供所有代码;

//------------------------------------
//----潘正宇,归并排序
//----2018.01.25
//------------------------------------
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <sstream>using namespace std;void merge(vector<int> &a, int l_begin, int l_end, int r_begin, int r_end);bool merge_sort(vector<int> &a,int begin,int end)
{//--若只传递了一个参数,无需进行排序,直接返回  if (begin >= end){return true;}int mid = (end + begin) / 2;merge_sort(a, begin, mid);merge_sort(a, mid + 1, end);//--经过上面的归并后两个子序列内部已经是有序的,若两个子序列中第二个子序列的第一个元素已经大于第一个子序列的最后一个元素,则不需要排序;if (a[mid] <= a[mid + 1]){return true;}merge(a, begin, mid, mid + 1, end);return true;
}void merge(vector<int> &a, int l_begin, int l_end,int r_begin,int r_end)
{//if (l_begin == l_end&&r_begin == r_end)     //--如果只有一个元素,则只需比较一次比较了;//{//  if (a[l_begin]>a[r_begin])// {//     int s = a[r_begin];//      a[r_begin] = a[l_begin];//     a[l_begin] = s;        //  }// return ;//}//int leng1 = l_end - l_begin + 1;int leng2 = r_end - r_begin + 1;//--创建两个临时的vector进行存放序列;vector<int> temp_L;vector<int> temp_R;for (int i = 0; i < leng1; i++){temp_L.push_back(a[l_begin+i]);}for (int i = 0; i < leng2; i++){temp_R.push_back(a[r_begin + i]);}int i = 0;int j = 0;while (i < leng1 && j < leng2){if (temp_L[i] <= temp_R[j]){a[l_begin + i + j] = temp_L[i];i++;}else{a[l_begin + i + j] = temp_R[j];j++;}}//--当某个其中一个序列的元素已经全部被放置进入归并后的序列,此时直接将第另一个剩下部分序列放入归并序列即可;while (i <leng1){a[l_begin + i + j] = temp_L[i];i++;}while (j <leng2){a[l_begin + i + j] = temp_R[j];j++;}return ;
}void main()
{ifstream inmyfile("123.txt");ofstream outmyfile("1234.txt");string line;vector<int> A;if (inmyfile){int x;while (getline(inmyfile,line)){istringstream is(line);string s;while (is>>s){x = atoi(s.c_str());A.push_back(x);}}}else{cout << "get input file was fail" << endl;}int len = A.size();merge_sort(A, 0, len-1);for (int i = 0; i < len; i++){outmyfile << A[i] << " ";}cout << endl;cout << A[10];system("pause");
}

已完。。

【算法】排序算法——归并排序相关推荐

  1. 数据算法排序之归并排序

    在你渐渐迷失在你的人生道路上的时候,千万不要因为走的太久,而忘记了我们为什么出发,做码农,也要清楚自己如何才能用有效的土地种植出 出色的产品,于是细节就需要把握一下. 如果你有兴趣可以关注一下公众号 ...

  2. 排序算法--排序算法汇总

    排序算法无疑是学习数据结构中的重点内容,本文将给出排序算法的汇总. 下面是具体的实现: #include<stdio.h> #include<stdlib.h> #includ ...

  3. java 算法 排序算法_Java七种排序算法以及实现

    Java常见七种排序算法以及实现 最近学习一些排序算法,怕自己以后忘记就打算整理起来供自己复习 萌新一枚学习Java没多久,以下仅供参考.如有错误希望大佬指正,欢迎大家在评论区交流探讨. 1.冒泡排序 ...

  4. 数据结构与算法 / 排序算法(2)

    一.归并排序 1.原理 采用分治思想.将数组分成前后两部分,先将这两部分进行排序,然后再将二者合并即可. 2.原地排序? 不属于原地排序.因为每次合并都需要申请大小为 n 的临时数组用于保存合并之后的 ...

  5. js 实现2的n次方计算函数_JS中数据结构与算法---排序算法

    排序算法的介绍 排序也称排序算法 (Sort Algorithm),排序是将 一组数据 , 依指定的顺序 进行 排列的过程 . 排序的分类 内部排序 : 指将需要处理的所有数据都加载 到 内部存储器( ...

  6. JAVA算法-排序算法

    排序算法的介绍 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程. 排序的分类: 1) 内部排序: 指将需要处理的所有数据都加载到内部存储器(内存)中进行 ...

  7. php+堆排序算法,排序算法-堆排序-php

    什么是堆排序 堆排序是我们经常使用的排序算法,它是利用堆的结构进行排序,堆是一种二叉树结构,并且它的父节点的值都大于子节点或者都小于子节点,如果大于,就是大顶堆,如果小于就是小顶堆. 根据堆的定义,我 ...

  8. 数据结构与算法 / 排序算法 / 堆排序

    一.定义 借助堆结构实现的排序算法被称为堆排序. 二.过程说明 1.建堆 (1)方法1 原地建堆,对于数组来说,从前往后:对于树来说,从下向上. 将数组的第一个元素作为堆顶,第二个元素做向堆中插入数据 ...

  9. 数据结构与算法 / 排序算法(3)

    一.桶排序(Bucket sort) 1.原理 将要排序的数据分到几个有序的桶里,每个桶里的数据再进行排序.桶内的数据排序完毕之后,再把桶里的数据依次取出,组成的序列就是有序的了. 2.原地排序? 属 ...

  10. 数据结构与算法 / 排序算法(1)

    零.前言 1.常用的排序算法总结 排序算法种类 时间复杂度 是否基于比较 冒泡.插入.选择 O(n^2) √ 快排.归并 O(nlogn) √ 桶.计数.基数 O(n) × 2.算法的内存消耗 - 原 ...

最新文章

  1. 转置卷积Transposed Convolution
  2. js获取url的参数
  3. [国家集训队]middle
  4. lstm需要优化的参数_LSTM的物理结构和一些细节
  5. STM32 FSMC/FMC原理保姆级讲解(一)
  6. 联想微型计算机怎么恢复系统,联想电脑台式一体机怎么重装系统 台式一体机重装系统...
  7. 好好学习,好好Show
  8. ssr提示服务器名无效_免费领取腾讯云服务器附带新手配置步骤(搭建网站)
  9. word公式编辑器复制粘贴未响应_word公式编辑器常见问题汇总,附带解决方法
  10. Dual Attention机制
  11. 【C语言进阶】⑤关于数组传参和指针传参辨析
  12. 如何快速从国外官网下载软件
  13. Discus论坛System Error界面修改标语
  14. 我CSDN博客被黑经历
  15. 程序开过多线程,导致hadoop作业无法运行成功——Call to hadoop1:9000 failed on lo cal exception: java.io.IOException: Coul
  16. C语言知识点汇总之一(全)
  17. Kibana自动刷新设置
  18. DataBinding → 数据绑定 (使用篇)
  19. 中国长江三峡工程开发总公司管理信息化案例
  20. 【你的偏航角还在飘吗】STM32CUBEMX+MPU6050+MPL运动处理库移植教程

热门文章

  1. [转]异步性能:了解 Async 和 Await 的成本
  2. 继承ListPreference后,去掉右边的图标
  3. 那些年,我写过的设置Windows系统变量的vbs脚本
  4. 请各位程序员 正在创业的 正在努力赚钱的 好好看看下面的话
  5. 什么是DataV数据可视化?
  6. Libreoffice实现office转pdf、html、jpg等格式数据
  7. Java 9 特性与示例
  8. java 课后习题 Vector类的 初使用
  9. chrome关闭自动更新 mac
  10. 【C语言】复合函数求值