归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之),将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序,若将两个有序表合并成一个有序表,称为二路归并

1、归并排序的基本思想

将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列

2、归并排序的算法描述

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾
 
归并排序其实要做两件事:

(1)“分解”——将序列每次折半划分(递归实现)

(2)“合并”——将划分后的序列段两两合并后排序

如何合并

在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。

这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。

先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。

我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。

每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中,最后将各段中余下的部分直接复制到R2中。

经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。

 
3、代码实现
 /* 将序列对半拆分直到序列长度为1*/
void MergeSort_UptoDown(int *num, int start, int end)
{
int mid = start + (end - start) / ; if (start >= end)
{
return;
} MergeSort_UptoDown(num, start, mid);
MergeSort_UptoDown(num, mid + , end); Merge(num, start, mid, end);
} void Merge(int *num, int start, int mid, int end)
{
int *temp = (int *)malloc((end-start+) * sizeof(int)); //申请空间来存放两个有序区归并后的临时区域
int i = start;
int j = mid + ;
int k = ; while (i <= mid && j <= end)
{
if (num[i] <= num[j])
{
temp[k++] = num[i++];
}
else
{
temp[k++] = num[j++];
}
} while (i <= mid)
{
temp[k++] = num[i++];
}
while (j <= end)
{
temp[k++] = num[j++];
} //将临时区域中排序后的元素,整合到原数组中
for (i = ; i < k; i++)
{
num[start + i] = temp[i];
} free(temp);
}
 
4、拆分过程

(图片来源:https://www.cnblogs.com/chengxiao/p/6194356.html)

完整代码:

 #include <stdio.h>
#include <stdlib.h> void MergeSort_UptoDown(int *num, int start, int end);
void Merge(int *num, int start, int mid, int end); int main()
{
/* 归并排序(升序) */
int num[] = {, , , , , , , , , };
int length = sizeof(num) / sizeof(num[]);
int i; MergeSort_UptoDown(num, , length - ); for (i = ; i < length; i++)
{
printf("%d ", num[i]);
} return ;
} /* 将序列对半拆分直到序列长度为1*/
void MergeSort_UptoDown(int *num, int start, int end)
{
int mid = start + (end - start) / ; if (start >= end)
{
return;
} MergeSort_UptoDown(num, start, mid);
MergeSort_UptoDown(num, mid + , end); Merge(num, start, mid, end);
} void Merge(int *num, int start, int mid, int end)
{
int *temp = (int *)malloc((end-start+) * sizeof(int)); //申请空间来存放两个有序区归并后的临时区域
int i = start;
int j = mid + ;
int k = ; while (i <= mid && j <= end)
{
if (num[i] <= num[j])
{
temp[k++] = num[i++];
}
else
{
temp[k++] = num[j++];
}
} while (i <= mid)
{
temp[k++] = num[i++];
}
while (j <= end)
{
temp[k++] = num[j++];
} //将临时区域中排序后的元素,整合到原数组中
for (i = ; i < k; i++)
{
num[start + i] = temp[i];
} free(temp);
}

归并排序(从上到下、从下到上)——C语言的更多相关文章

  1. react + iscroll5 实现完美 下拉刷新,上拉加载

    经过几天的反复折腾,总算做出一个体验还不错的列表页了,主要支持了下拉刷新,上拉加载两个功能. 一开始直接采用了react-iscroll插件,它是基于iscroll插件开发的组件.但是开发过程中,发现 ...

  2. 在SpringMVC框架下实现文件的 上传和 下载

    在eclipse中的javaEE环境下:导入必要的架包 web.xml的配置文件: <?xml version="1.0" encoding="UTF-8" ...

  3. 原生JS实现分页效果2.0(新增了上一页和下一页,添加当前元素样式)

    虽然写的很烂,但至少全部都是自己写的,因为这个没有固定的顺序,所以就没有封装,如果你技术好的话,可以你写的分享给我,谢谢. <!DOCTYPE html><html lang=&qu ...

  4. iOS MJRefresh下拉刷新(上拉加载)使用详解

    下拉刷新控件目前比较火的有好几种,本人用过MJRefresh 和 SVPullToRefresh,相对而言,前者比后者可定制化.拓展新都更高一点. 因此本文着重讲一下MJRefresh的简单用法. 导 ...

  5. js获取上一个月、下一个月格式为yyyy-mm-dd的日期

    /** * 获取上一个月 * * @date 格式为yyyy-mm-dd的日期,如:2014-01-25 */ function getPreMonth(date) { var arr = date. ...

  6. PHP实现上一篇、下一篇

    //php实现上一篇.下一篇 获取当前浏览文章id $id = isset($_GET[ ? intval($_GET['id']) : ""; 下一篇文章 $query = my ...

  7. SVPullToRefresh​ 下拉刷新,上拉加载

    https://github.com/Sephiroth87/ODRefreshControl 类似刷新控件,类似qq动画的那种刷新. 一.下载第三方库 https://github.com/samv ...

  8. Android PullToRefreshListView上拉刷新和下拉刷新

    PullToRefreshListView实现上拉和下拉刷新有两个步骤: 1.设置刷新方式 pullToRefreshView.setMode(PullToRefreshBase.Mode.BOTH) ...

  9. c++(vs上)与g++(linux下)对于++操作的汇编代码解读

    先来看一个代码,估计很多同学都碰到过其中的某一个. #include <stdio.h> #include <iostream> using namespace std; in ...

  10. ListView(2)最简单的上拉刷新,下拉刷新

    最简单的上拉刷新和下拉刷新,当listview滚动到底部时向上拉刷新数据.当listview滚动到最顶部时下拉刷新.       图1,上拉刷新 图2,下拉刷新 1,设置lisview,加载heade ...

随机推荐

  1. jQuery-ajax-.load方法

    使用jQuery封装的ajax是非常好用的,这个里面提供了几个比较好用的方法. load(url[,data, callback])方法: 说明:这个是jQuery中的最底层方法$.ajax()封装的 ...

  2. CentOS 7编译安装Redis

    安装编译相关依赖 CentOS/Fedora yum install gcc gcc-c++ cmake tcl 下载Redis源码包 curl -o redis-4.0.10.tar.gz http ...

  3. BFS(一):广度优先搜索的基本思想

    广度优先搜索BFS(Breadth First Search)也称为宽度优先搜索,它是一种先生成的结点先扩展的策略. 在广度优先搜索算法中,解答树上结点的扩展是按它们在树中的层次进行的.首先生成第一层 ...

  4. SqlDataReader的用法 转自https://www.cnblogs.com/sunxi/p/3924954.html

    datareader对象提供只读单向数据的快速传递,单向:您只能依次读取下一条数据;只读:DataReader中的数据是只读的,不能修改;相对地,DataSet中的数据可以任意读取和修改 01.usi ...

  5. MySQL 全文索引实现简单版搜索引擎

    目录 前言 使用 三种类型的全文搜索方式 相关参数 测试innodb引擎使用全文索引 准备 使用默认方式创建全文索引 使用ngram分词解析器创建全文索引 结论 前言 只有Innodb和myisam存 ...

  6. SpringBoot开发案例之分布式集群共享Session

    前言 在分布式系统中,为了提升系统性能,通常会对单体项目进行拆分,分解成多个基于功能的微服务,如果有条件,可能还会对单个微服务进行水平扩展,保证服务高可用. 那么问题来了,如果使用传统管理 Sessi ...

  7. find文件删除

    find /root/title/test -type f -name '*.txt' -exec rm {} \;   查找并删除test文件夹下所有txt文件 find /root/title/t ...

  8. Spring Cloud 之 Hystrix.

    一.概述  在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依 ...

  9. c语言学习书籍推荐《C语言学习路线图•C语言必须知道的300个问题》下载

    下载地址:点我 <C语言学习路线图•C语言必须知道的300个问题>以基础知识为框架,介绍了c语言各部分知识所对应的常见开发疑难问题,并作了透彻地解析.<C语言学习路线图•C语言必须知 ...

  10. 手动启动log4j|nginx实现http https共存

    手动加载log4j.xml文件 DOMConfigurator.configure("src/main/resources/log4j.xml"); log4j.propertie ...