经典排序算法 — C#版本(中)
归并排序比较适合大规模得数据排序,借鉴了分治思想。
归并排序原理

自古以来,分久必合合久必分。
我们可以这样理解归并排序,分-分到不能分为止,然后合并。
使用递归将问题一点一点分解,最后进行合并。
分而治之 (merge_sort)
提到递推,我们使用地递推解决问题,首先要分析出递推公式、明确结束条件。
递推公式: merge_sort(i...n)=merge( merge_sort(i...j), merge_sort(j+...n) ) 结束条件:
i>=n
分久必合(merge)
将两个有序的数组进行合并,这样整个数组也就是排序好的数组了。
那么怎么进行合并呢?-- (i...j) 和 (j+1...n) 重新排序后,重新放入原来的数组 (i...n)

两组数组 [3, 8, 9, 11] vs [1, 2, 5, 7]
两个游标 蓝色 和 红色
3>1,1小,1入新数组,红色游标后移一位,继续比较...

3>2,2小,2入数组,红色游标后移一位

3<5,3小,3入数组,蓝色游标后移一位

8>5,5小,5入数组,红色游标后移一位

8>7,7小,7入数组,红色游标后移,右侧数组全部转移完毕

当有一组数组全部转移完毕,那么剩下的一组中的全部元素依次转入到新数组中,新数组正式成为一个有顺序的数组

通过以上两点:递推公式和合并思想,我们使用代码实现一下:
1、如下图:递归方式 进行分解,然后使用合并代码进行合并。
/// <summary>
/// 递归调用
/// </summary>
/// <param name="a">原始数组</param>
/// <param name="p">分割点</param>
/// <param name="r">结束位置</param>
public static void MergrSortInternally(int[] a, int p, int r)
{
//结束条件
if (p >= r)
return; //切割点
int q = p + (r - p) / ; //分而治之
MergrSortInternally(a, p, q); MergrSortInternally(a, q + , r); //合并 A(a, p, q) 和 A(a, q + 1, r)
Merage(a, p, q, r); }

2、我们再来看看合并逻辑
参数:原始数组,开始的地方,切割的地方,结束的地方
逻辑:两个切割数组的各自的游标
申请同样大小的临时数组
循环比较;小的入临时,游标后移;知道有一个数组空了为止
找到剩下不为空的那个数组,将剩余元素入临时
将临时数组,找到原始数组的对应为止进行覆盖
/// <summary>
/// 合并
/// </summary>
/// <param name="a">原始数组</param>
/// <param name="p">起始点</param>
/// <param name="q">切割点</param>
/// <param name="r">结束点</param>
public static void Merage(int[] a, int p, int q, int r)
{
// i 和 j = 两个数组的游标
int i = p;
int j = q + ; // 临时数组的游标
int k = ; // 临时数组
int[] temp = new int[r - p + ]; //最小入队,直到其中一个空空如也为止
while (i <= q && j <= r)
{
if (a[i] <= a[j])
{
temp[k] = a[i];
++k;
++i;
}
else
{
temp[k] = a[j];
++k;
++j;
}
} // 找到另一个不为空的,找到剩下的元素
int start = i;
int end = q; if (j <= r)
{
start = j;
end = r;
} // 剩余数组拷贝到临时数组 temp
while (start <= end)
{
temp[k++] = a[start++];
} // 将temp覆盖到a[p...r]
for (i = ; i <= r - p; ++i)
{
a[p + i] = temp[i];
}
}


归并排序性能分析
Q:是不是稳定排序?
A:是
对于这两组数组 A[p...q] 和 A[q+1...r] 来说
代码中也是这样实现的,a[i]就是左侧数组,a[j]就是右侧数组,保证相等时左侧优先入队即可。注意 等号位置。

Q:是否是原地排序?
A:当然不是
因为我们在合并代码时候,申请了同样大小的内存空间。
但是对于这里的归并排序的空间复杂度又是多少呢?
虽然牵扯到了递归,但是临时变量这里会在一个函数结束后栈会释放,所以空间复杂度是O(n)
Q:时间复杂度又是多少呢?
A:O(n log n)
我们对 n 个元素的归并排序时间记作 T(n),
分解函数分解两个子数组的时间是T(n/2)
合并函数时间复杂度是O(n)
T(1)=C; n=1
T(n)=2*T(n/2)+ n; n>1
T(n) = 2*T(n/2) + n
= 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
= 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
= 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n
......
= 2^k * T(n/2^k) + k * n
T(n) = 2^k * T(n/2^k) + k * n
当 T(n/2^k) = T(1)=> k = log2 n
即:T(n) = Cn + n log2 n => O(n log n)
经典排序算法 — C#版本(中)的更多相关文章
- 经典排序算法总结与实现 ---python
原文:http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/ 经典排序算法在面试中占有很大的比重,也是基础,为了未雨绸缪,在寒假里整理并用P ...
- 【最全】经典排序算法(C语言)
算法复杂度比较: 算法分类 一.直接插入排序 一个插入排序是另一种简单排序,它的思路是:每次从未排好的序列中选出第一个元素插入到已排好的序列中. 它的算法步骤可以大致归纳如下: 从未排好的序列中拿出首 ...
- python 经典排序算法
python 经典排序算法 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.常见的内部排序算 ...
- 十大经典排序算法最强总结(含JAVA代码实现)(转)
十大经典排序算法最强总结(含JAVA代码实现) 最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每 ...
- 十大经典排序算法最强总结(含Java、Python码实现)
引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...
- 十大经典排序算法(java实现、配图解,附源码)
前言: 本文章主要是讲解我个人在学习Java开发环境的排序算法时做的一些准备,以及个人的心得体会,汇集成本篇文章,作为自己对排序算法理解的总结与笔记. 内容主要是关于十大经典排序算法的简介.原理.动静 ...
- python基础__十大经典排序算法
用Python实现十大经典排序算法! 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大, ...
- 经典排序算法 – 插入排序Insertion sort
经典排序算法 – 插入排序Insertion sort 插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...
- 经典排序算法及python实现
今天我们来谈谈几种经典排序算法,然后用python来实现,最后通过数据来比较几个算法时间 选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据 ...
随机推荐
- mvn -DskipTests和-Dmaven.test.skip=true区别
在使用mvn package进行编译.打包时,Maven会执行src/test/java中的JUnit测试用例,有时为了跳过测试,会使用参数-DskipTests和-Dmaven.test.skip= ...
- Python定时任务框架APScheduler
http://blog.csdn.net/chosen0ne/article/details/7842421 APScheduler是基于Quartz的一个Python定时任务框架,实现了Quartz ...
- nodejs版本更新问题:express不是内部或外部命令
版本更新后,我们使用熟悉的npm install -g express命令安装,但是,安装成功之后居然提示express不是内部或外部命令. nodejs小问题:[1]express不是内部或外部命令 ...
- GitHub 系列之「Git 进阶」
1.用户名和邮箱 我们知道我们进行的每一次 commit 都会产生一条 log,这条 log 标记了提交人的姓名与邮箱,以便其他人方便的查看与联系提交人,所以我们在进行提交代码的第一步就是要设置自己的 ...
- 在Windows Server 2008 R2下搭建jsp环境(二)-mysql的下载安装
个人推荐java开发过程中的数据库首选MYSQL,MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司.MySQL是一种关联数据库管理系统,关联数据库将数据保 ...
- maven国内镜像(国内oschina的maven服务器关了)
Maven是官方的库在国外,连下载速度很慢.国内oschina的maven服务器很早之前就关了.今天发现阿里云的一个中央仓库,亲测可用. 找到E:\maven\apache-maven-3.5.2\c ...
- Axure使用——创建折叠菜单
1.先添加动态面板 2.往动态面板中添加矩形 3.接着先隐藏下面的矩形(也就是你要折叠起来的内容) 4.一定要注意: 5.添加动态面板的状态 6.把之前做的那个矩形全部复制到state1中 7.把之前 ...
- HTTP协议中GET和POST区别
GET一般用于获取和查询资源信息:POST一般用于更新信息,表示可能修改服务器上资源的请求 GET请求一般是幂等的 GET请求数据会附加在url之后,POST请求数据放到request-body中 G ...
- 认识容器和Docker(一)
前言: 这句话应该是开发人员经常挂在嘴边的吧! “在我的机器上是正常工作的啊,MD,怎么到你这就不行了?” 开发人员就会联想到: 1. 肯定是你环境有问题: 2. 要么就是你个傻*不会用吧: 带着这句 ...
- Spark学习之数据读取与保存总结(一)
一.动机 我们已经学了很多在 Spark 中对已分发的数据执行的操作.到目前为止,所展示的示例都是从本地集合或者普通文件中进行数据读取和保存的.但有时候,数据量可能大到无法放在一台机器中,这时就需要探 ...