归并排序比较适合大规模得数据排序,借鉴了分治思想。

归并排序原理

自古以来,分久必合合久必分。

我们可以这样理解归并排序,分-分到不能分为止,然后合并。

使用递归将问题一点一点分解,最后进行合并。

分而治之 (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#版本(中)的更多相关文章

  1. 经典排序算法总结与实现 ---python

    原文:http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/ 经典排序算法在面试中占有很大的比重,也是基础,为了未雨绸缪,在寒假里整理并用P ...

  2. 【最全】经典排序算法(C语言)

    算法复杂度比较: 算法分类 一.直接插入排序 一个插入排序是另一种简单排序,它的思路是:每次从未排好的序列中选出第一个元素插入到已排好的序列中. 它的算法步骤可以大致归纳如下: 从未排好的序列中拿出首 ...

  3. python 经典排序算法

    python 经典排序算法 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.常见的内部排序算 ...

  4. 十大经典排序算法最强总结(含JAVA代码实现)(转)

    十大经典排序算法最强总结(含JAVA代码实现)   最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每 ...

  5. 十大经典排序算法最强总结(含Java、Python码实现)

    引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...

  6. 十大经典排序算法(java实现、配图解,附源码)

    前言: 本文章主要是讲解我个人在学习Java开发环境的排序算法时做的一些准备,以及个人的心得体会,汇集成本篇文章,作为自己对排序算法理解的总结与笔记. 内容主要是关于十大经典排序算法的简介.原理.动静 ...

  7. python基础__十大经典排序算法

    用Python实现十大经典排序算法! 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大, ...

  8. 经典排序算法 – 插入排序Insertion sort

    经典排序算法 – 插入排序Insertion sort  插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...

  9. 经典排序算法及python实现

    今天我们来谈谈几种经典排序算法,然后用python来实现,最后通过数据来比较几个算法时间 选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据 ...

随机推荐

  1. 更多细节的理解RSA算法

    一.概述 RSA算法是1977年由Ron Rivest.Adi Shamir 和 Leonard Adleman三人组在论文A Method for Obtaining Digital Signatu ...

  2. filddler一个抓包修改的工具 貌似很强大2017.12.07

    filddler直接百度下载  还没弄懂怎么用  有待研究!

  3. html5中viewport与meta详解

    网上解释手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中 ...

  4. 安装Navicat for MySQL

    注: 以下内容引自 https://www.cnblogs.com/da19951208/p/6403607.html Navicat for MySQL下载.安装与破解   一:下载Navicat ...

  5. ResultSet,RowSet,OracleCachedRowSet和RowSetMetaData区别及联系

    在java主要涉及到数据开发的过程中,我们会和数据库打交道很多,其中使用了数据集比如ResultSet和RowSet,经常使用两种,还有其它的一些,那么这两种的主要区别是什么呢?我们先来看它们引入的方 ...

  6. go语言 nsq源码解读四 nsqlookupd源码options.go、context.go和wait_group_wrapper.go

    本节会解读nsqlookupd.go文件中涉及到的其中三个文件:options.go.context.go和wait_group_wrapper.go. options.go 123456789101 ...

  7. [Usaco2005 nov]Grazing on the Run 边跑边吃草 BZOJ1742

    分析: 首先,连续选择一段必定最优... 区间DP,f[i][j]表示从i开始,连续j个被吃掉了,并且,牛在i处,g[i][j]则表示在i+j-1处 f[i][j]可以从g[i+1][j]和f[i+1 ...

  8. zookeeper源码 — 二、集群启动—leader选举

    上一篇介绍了zookeeper的单机启动,集群模式下启动和单机启动有相似的地方,但是也有各自的特点.集群模式的配置方式和单机模式也是不一样的,这一篇主要包含以下内容: 概念介绍:角色,服务器状态 服务 ...

  9. eShopOnContainers 知多少[7]:Basket microservice

    引言 Basket microservice(购物车微服务)主要用于处理购物车的业务逻辑,包括: 购物车商品的CRUD 订阅商品价格更新事件,进行购物车商品同步处理 购物车结算事件发布 订阅订单成功创 ...

  10. 怎么构建vue-cli项目

    1.安装node.js(已安装可直接跳过,建议查看node版本,node -v): 2.npm包管理器,是集成在node中的,可跳过(npm -v): 3.由于npm的有些资源被墙,为了更快更稳定,所 ...