归并排序:二路归并

news/2024/5/17 17:12:44 标签: 归并排序, 递归, 合并, merge, 二路归并

归并排序(Merge Sort)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。

归并排序的具体做法:

  1. 把原序列不断地递等分,直至每等份只有一个元素,此时每等份都是有序的。
  2. 相邻等份合,不断合并,直至合并完全。

二路归并

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序最常用的是二路归并,即把两个小的有序的序列和并成一个大的有序序列:合二为一。

一个二路归并的流程图是这样的:

多路归并无非是多个有序的小序列合并成一个大的有序序列,道理和二路归并一样。

先来看下如何把两个有序的序列合并成一个大的有序序列,代码如下:

/*
 *把有序序列a和b,合并成c 
 *该算法成立前提: a和b已经有序  
 */ 
void merge(int a[], int na, int b[], int nb, int c[])
{
	if(a && b && c && na >0 && nb >0)
	{
		int i,j,k;
		i = j = k = 0;
		//不断地比较a和b的头部元素,较小的存入c 
		while(i < na && j < nb)
		{
			if(a[i] <= b[j]) // <= 保持算法的稳定性
				c[k++] = a[i++];
			else
				c[k++] = b[j++];
			/*另一种更有效的做法是这样的 
			while(i < na && a[i] <= b[j])
				c[k++] = a[i++];
			while(j < nb && b[j] < a[i])
				c[k++] = b[j++];
			*/
		}
		//把a或b中剩余的元素直接存入c 
		/*  也可以这样:
	     *  memcpy(c+k, a+i, (na-i)sizeof(int));
	     * 下同
	     */
		while(i < na)
			c[k++] = a[i++];
		while(j < nb)
			c[k++] = b[j++];
	}
}

可以看出,二路归并的时间复杂度是O(n),n是原序列的数据规模。以上代码是归并排序的基础,弄懂了它,就很好写归并排序了,看下归并排序的流程图:


可以看出,上半部分不断地递归深入:不断地均分原序列,直到每一部分只含有一个元素。下半部分,开始递归返回,通过反复调用二路归并算法,把相邻的有序子序列合并成一个规模更大的序列。

理解了这些,相信就很容易写出归并排序的代码了:

//把[first, mid]和[mid+1, last]范围内的数据合并  
void mergeArray(int a[], int b[], int first, int mid, int last)
{
	int i, j, k;
	i = first, j = mid + 1, k = 0;
	while (i <= mid && j <= last)
	{
		while(i <= mid && a[i] <= a[j])
			b[k++] = a[i++];
		while(j <= last && a[j] < a[i])
			b[k++] = a[j++];	
	}
	/*  也可以这样:
	 *  memcpy(b+k, a+i, (mid-i+1)sizeof(int));
	 * 下同
	 */
	while (i <= mid)
		b[k++] = a[i++];
	while (j <= last)
		b[k++] = a[j++];
	//[first,last]范围内的数据已有序,则写回原数组
	for (i = 0; i < k; i++)
		a[first + i] = b[i];
}
void mergesort(int a[], int b[], int first, int last)
{
	if (first < last)
	{
		int mid = first + ((last - first) >> 1);
		mergesort(a, b, first, mid);
		mergesort(a, b, mid + 1, last);
		mergeArray(a, b, first, mid, last);
	}
}
void MergeSort(int a[], int n)
{
	if (a && n > 1)
	{
		int *b = new int[n];  //构建辅助数组
		mergesort(a, b, 0, n - 1);
		delete[]b;
	}
}


在排序过程中,我们使用了一个相同大小的临时辅助数组。

算法分析:

1.算法的复杂度

对数组长度为n的序列进行归并排序,则大约要进行logn次归并,每一次合并都是线性时间O(n)。故粗略的计算出归并排序的时间复杂度是O(nlogn)(最好、最差都是这样)。空间复杂度是O(n)。详细的时间复杂度分析是这样的:

对长度为n的序列归并排序,需要递归的对长度为n/2的子序列进行归并排序,最后把两段子序列二路归并。递推关系是这样的:T(n)=2T(n/2)+O(n),显然T(1)=O(1),解得T(n)=o(nlogn)。

2.稳定性

归并排序是稳定的,并且是时间复杂度为o(nlogn)的几种排序(快速排序、堆排序)中唯一稳定的排序算法。

3.存储结构

顺序存储和链式存储都行。

另外,归并排序多用于外排序中。


转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/34463409


若是有所帮助,顶一个哦!



所有内容的目录

  • CCPP Blog 目录



    http://www.niftyadmin.cn/n/1802156.html

    相关文章

    树、二叉树基础

    前言 前面介绍的栈、队列都是线性结构(linear structure)。而树是非线性结构(non-linear structure)。因此&#xff0c;树中的元素之间一般不存在类似于线性结构的一对一的关系&#xff0c;更多地表现为多对多的关系。直观地看&#xff0c;它是数据元素(在树中称为节点)按分支…

    二分检索

    二分检索 概述二分检索(Binary Search)也叫二分查找&#xff0c;是应用于有序表上的一种检索方法。二分检索的思想是&#xff1a;由于序列已经有序&#xff0c;故不需要顺序遍历&#xff0c;每次只需和序列中间位置的元素进行比较即可&#xff0c;以此确定下次查找的位置。显然…

    索引排序

    索引排序 在排序时&#xff0c;若是数据很复杂&#xff0c;对数据的移动显然是费时的。若把数据移动改为索引(或指针)移动&#xff0c;则减少了操作复杂度。索引排序&#xff0c;也叫地址排序&#xff0c;就是这种排序思想。 索引含义 根据索引的含义不同&#xff0c;索引排…

    串的匹配:朴素匹配KMP算法

    引言 字符串的模式匹配是一种常用的操作。模式匹配(pattern matching)&#xff0c;简单讲就是在文本(text&#xff0c;或者说母串str)中寻找一给定的模式(pattern)。通常文本都很大&#xff0c;而模式则比较短小。典型的例子如文本编辑和DNA分析。在进行文本编辑时&#xff0c…

    娓娓道来c指针 (0)c语言的梦魇:c指针

    (0)c语言的梦魇&#xff1a;c指针序c语言中有一个重点&#xff1a;c指针。它也是一个难点。当然&#xff0c;这是一句废话&#xff1a;重点往往也是难点。在c标准中&#xff0c;对指针的定义是这样的&#xff1a;指针的类型是derived from其它类型&#xff0c;也就是说指针的类…

    娓娓道来c指针 (1)指针就是地址

    (1)指针就是地址 首先明确一个观点&#xff1a;指针就是地址。这是理解指针的起始一步。 直观感受下&#xff0c;变量的地址int main() {int foo;int *foo_p;foo 5;foo_p &foo;printf(" foo...%d\n", foo);printf("*foo_p...%d\n", *foo_p);printf…

    娓娓道来c指针 (2)内存分配

    (2)内存分配 c语言中描述变量的时候常用的两个用语 1.作用域&#xff1a;也叫可见域&#xff0c;指的是变量的作用范围。在哪个范围内&#xff0c;该变量是可见的、可以使用的。 2.生存期&#xff1a;也叫存储期&#xff0c;指的是变量从创建到销毁的生存时间段。 作用域和…

    娓娓道来c指针 (3)指针和数组

    (3)指针和数组 在c中指针和数组似乎有着千丝万缕的关系。其实它们不是一回事&#xff1a;指针是指针&#xff0c;数组是数组&#xff0c;两者不相同。 说它们有关系&#xff0c;不过是因为常见这样的代码&#xff1a; int main() {int array[] {1,2,3,4,5};int n sizeof(ar…