小小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的那个人又 ...
随机推荐
- 【LeetCode】028. Implement strStr()
Implement strStr(). Return the index of the first occurrence of needle in haystack, or -1 if needle ...
- python IOError: cannot identify image file
转:http://blog.csdn.net/sinat_25704999/article/details/50118465
- position:sticky属性测试
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- angular : copy vs extend
While using AngularJS, we come across some situation in which we need to copy one object to another ...
- mysql update不支持子查询更新
先看示例: SELECT uin,account,password,create_user_uin_tree FROM sys_user 结果: 表中的create_user_uin_tree标识该条 ...
- Rails的静态资源管理(二)—— 如何使用 Asset Pipeline
官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...
- Nginx简单入门教学,包学包会,让你不再依赖伪大神!
这篇教程简单介绍了 nginx 并且讲解了一些 nginx 可以解决的简单任务.这里,我们假设 nginx 已经安装在读者的机器上.如果没有,可以看一下如何安装 nginx.这篇教程主要讲解的是如果启 ...
- 12-01Js表单验证和JsWindow
一.表单验证form 1.创建一个新的表单: <form id="id是唯一的,不可重复" name=“可重复”,method="post/get",ac ...
- Qt opencv开发环境
在.pro文件中添加 INCLUDEPATH += C:\opencv\build\include\ #头文件路径 C:\opencv\build\include\opencv\ C:\opencv\ ...
- GET与POST方法
HTTP中的GET,POST,PUT,DELETE对应着对这个资源的查,改,增,删4个操作.GET一般用于获取/查询资源信息,而POST一般用于更新资源信息. 1.根据HTTP规范,GET用于信息获取 ...