小小c#算法题 - 8 - 归并排序 (Merging Sort)
“归并”的含义是将两个或两个以上的有序序列组合成一个新的有序序列。这个“归并”可以在O(n+m)的数量级上实现,但这同时也需要O(n+m)的空间复杂度。具体为:首先分配一个新的长度为n+m的空序列,然后对于序列1(长度为n),序列2(长度为m),从每个序列的第一个元素开始比较,将较小的元素放入新的序列,然后较小元素原来所在序列的下标加1,这样一直比较下去,最终把这两个序列有序的放入新的序列中。在2-路归并排序中,这里的序列1,序列2表现为待排序列的两个相邻子序列。
2-路归并排序的定义:假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2(上取整)个长度为2或1的有序子序列;再两两归并,......,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。
那么可以看出,2-路归并排序中的核心操作是将一维数组中相邻的两个有序子序列归并为一个有序序列,代码如下:
传入一个数组,将这个数组中的两个有序子序列(low ~ middle, middle + 1 ~high)合并成一个有序的子序列。先把序列copy一份,用来后面比较元素使用。
static void Merge(int[] numbers, int low, int middle, int high)
{
int[] temp = new int[numbers.Length];
numbers.CopyTo(temp, );
int index = low;
int m = middle + ;
while (low <= middle && m <= high)
{
if (temp[low] <= temp[m])
{
numbers[index++] = temp[low++];
}
else
{
numbers[index++] = temp[m++];
}
} // 比较循环结束后,左边(低位)子序列有剩余元素的情况
while (low <= middle)
{
numbers[index++] = temp[low++];
} // 比较循环结束后,右边(高位)子序列有剩余元素的情况
while (m <= high)
{
numbers[index++] = temp[m++];
}
}
上面核心操作的算法已经实现了,下面就是怎么通过调用上述算法来对序列进行排序了。这里采用了递归的思想,当对一个序列进行排序时,分别对其左,右子序列进行排序(一般从中间划分),左,右子序列有序后,调用Merger方法合并这两个子序列,得到整个的有序序列。递归停止的条件是序列长度只为1的时候。代码如下:
static void MergeSort(int[] numbers, int low, int high)
{
// low == high时序列长度为1,是停止递归的条件
if (low != high)
{
int middle = (low + high) / ;
MergeSort(numbers, low, middle);
MergeSort(numbers, middle + , high);
Merge(numbers, low, middle, high);
}
}
为了方便调用,对MergeSort又封装一次:
static void MSort(int[] numbers)
{
MergeSort(numbers, , numbers.Length - );
}
下面是对MergeSort方法的调用(这个例子使用控件台应用程序类型):
static void Main(string[] args)
{
int[] numbers = { , , , , , , , , , , , , };
MSort(numbers); foreach (int i in numbers)
{
Console.Write(i.ToString() + " ");
}
}
归并排序是稳定的排序,Merge方法的时间复杂度为O(n), 要实现排序,需调用logn次Merge方法,所以归并排序的时间复杂度为O(n*logn)。由于排序时需要额外的临时序列的copy,所以空间复杂度为O(n),这也是归并排序的缺点。
一个可以优化的地方:
Merger方法中,每次都要copy一整份序列。但其实只要copy其中的要比较的两个子序列中的元素即可,所以有优化代码如下:
static void Merge(int[] numbers, int low, int middle, int high)
{
int[] temp = new int[high - low + ];
for (int i = low, j = ; i <= high; i++)
{
temp[j++] = numbers[i];
} int index = low;
middle -= low;
high -= low;
low = ;
int m = middle + ;
while (low <= middle && m <= high)
{
if (temp[low] <= temp[m])
{
numbers[index++] = temp[low++];
}
else
{
numbers[index++] = temp[m++];
}
} while (low <= middle)
{
numbers[index++] = temp[low++];
} while (m <= high)
{
numbers[index++] = temp[m++];
}
}
小小c#算法题 - 8 - 归并排序 (Merging Sort)的更多相关文章
- 小小c#算法题 - 9 - 基数排序 (Radix Sort)
基数排序和前几篇博客中写到的排序方法完全不同.前面几种排序方法主要是通过关键字间的比较和移动记录这两种操作来实现排序的,而实现基数排序不需要进行记录项间的比较.而是把关键字按一定规则分布在不同的区域, ...
- 小小c#算法题 - 7 - 堆排序 (Heap Sort)
在讨论堆排序之前,我们先来讨论一下另外一种排序算法——插入排序.插入排序的逻辑相当简单,先遍历一遍数组找到最小值,然后将这个最小值跟第一个元素交换.然后遍历第一个元素之后的n-1个元素,得到这n-1个 ...
- 归并排序(Merging Sort)
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- 数据结构 - 归并排序(merging sort)
归并排序(merging sort): 包含2-路归并排序, 把数组拆分成两段, 使用递归, 将两个有序表合成一个新的有序表. 归并排序(merge sort)的时间复杂度是O(nlogn), 实际效 ...
- 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历
在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...
- 数据结构 - 归并排序(merging sort) 具体解释 及 代码
归并排序(merging sort) 具体解释 及 代码 本文地址: http://blog.csdn.net/caroline_wendy 归并排序(merging sort): 包括2-路归并排序 ...
- 排序算法二:归并排序(Merge sort)
归并排序(Merge sort)用到了分治思想,即分-治-合三步,算法平均时间复杂度是O(nlgn). (一)算法实现 private void merge_sort(int[] array, int ...
- 小小c#算法题 - 6 - 快速排序 (QuickSort)
快速排序是排序算法中效率比较高的一种,也是面试常被问到的问题. 快速排序(Quick Sort)是对冒泡排序的一种改进.它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字 ...
- 小小c#算法题 - 12 - Joseph Circle(约瑟夫环)
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数(从1开始报数),数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又 ...
随机推荐
- rabbitmq的vhost与用户管理
当我们在创建用户时,会指定用户能访问一个虚拟机,并且该用户只能访问该虚拟机下的队列和交换机,如果没有指定,默认的是”/”;一个rabbitmq服务器上可以运行多个vhost,以便于适用不同的业务需要, ...
- 调整 WiFi 驱动设置让 WiFi 信号更稳定
调整 WiFi 驱动设置让 WiFi 信号更稳定 修改 WiFi 驱动中 的设置,将 Power Saving Mode 的值改为 CAM.
- Linux动态gif图的录制
Linux动态gif图的录制 Linux动态gif图的录制 byzanz的安装与使用 recordmydesktop再convert成gif 参考资料 前几天写了两篇博客vim的配置和Vim的自动代码 ...
- HIVE-分区表详解以及实例
HIVE中的分区表是什么,我们先看操作,然后再来体会. 创建一个分区表,分区的单位时dt和国家名 hive> create table logs(ts bigint,line string) & ...
- java文本文件读写
java的IO系统中读写文件使用的是Reader和Writer两个抽象类,Reader中的read()和close()方法是抽象方法,Writer中的write().flush()和close()方法 ...
- 开启VMSS Autoscale的报警功能
VMSS可以自动的实现Scale Out和Scale in.在VMSS做自动操作的时候,可以通过配置通知服务,通知VMSS的状态. 具体实现方式: 1, 在portal中选择"监视器&quo ...
- 机器学习:决策树(CART 、决策树中的超参数)
老师:非参数学习的算法都容易产生过拟合: 一.决策树模型的创建方式.时间复杂度 1)创建方式 决策树算法 既可以解决分类问题,又可以解决回归问题: CART 创建决策树的方式:根据某一维度 d 和某一 ...
- spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程
它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...
- Java-API-Package:org.springframework.web.bind.annotation
ylbtech-Java-API-Package:org.springframework.web.bind.annotation 1.返回顶部 1. @NonNullApi @NonNullField ...
- AngularJS:Bootstrap
ylbtech-AngularJS:Bootstrap 1.返回顶部 1. AngularJS Bootstrap AngularJS 的首选样式表是 Twitter Bootstrap, Twitt ...