经典排序算法 — 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)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据 ...
随机推荐
- MySQL中group_concat函数深入理解
本文通过实例介绍了MySQL中的group_concat函数的使用方法,比如select group_concat(name) . 一.MySQL中group_concat函数 完整的语法如下: gr ...
- 12.app后端如何选择合适的数据库产品
app后端的开发中,经常要面临的一个问题是:数据放在哪里? mysql ?redis?mongodb? 现在有这么多优秀的开源数据库产品,怎么根据业务场景来选择合适的数据? 常用的数据库产品的优缺点又 ...
- 1. 开篇-springboot环境搭建
最初学习strurs2时,虽然觉得也挺好用的,但也有一些不便的地方:1. 模型绑定必须要在Action中声明对应模型的成员变量:2. Action中对外提供调用的接口必须明确注明:3. 要声明一大堆的 ...
- 查询订阅某topic的所有consumer group(Java API)
在网上碰到的问题,想了下使用现有的API还是可以实现的. 首先,需要引入Kafka服务器端代码,比如加入Kafka 1.0.0依赖: Maven <dependency> <grou ...
- logrus_hook.go
package) //表示自身栈中跳过6个,:] entry.Data["file"] = fileName entry.Data["func" ...
- 【bzoj 2303】【Apio2011】方格染色
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2303 题解: 很神奇的思路,膜一发大佬http://www.cnblogs.com/HHsh ...
- BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树
BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...
- ELK---日志分析系统
ELK就是一套完整的日志分析系统 ELK=Logstash+Elasticsearch+Kibana 统一官网https://www.elastic.co/products ELK模块说明 Logst ...
- 从壹开始前后端 [vue后台] 之二 || 完美实现 JWT 滑动授权刷新
缘起 哈喽大家周一好!不知道小伙伴们有没有学习呀,近来发现各种俱乐部搞起来了,啥时候群里小伙伴也搞一次分享会吧,好歹也是半千了(时间真快,还记得5个月前只有20多人),之前在上个公司,虽然也参与组织过 ...
- zabbix微信报警信息优化模板
--------------------------------告警模板1-------------------------------------- 默认标题 告警项目: {TRIGGER.NAME ...