排序问题-归并排序

归并排序是递归的一个典型应用,是用空间换时间的典型例子(需要一个临时数组存放以排序的序列)。在各个排序算法中其比较的次数是最少的,在最坏的情况下的运行时间是O(NlogN)。

归并排序是一个递归-合并的过程,基本操作是将两个已经排好序的表扫描一遍依次有序的存放到第三个表中。在递归的过程中,每次递归都是一次划分,将一个序列从中划分成两个子序列(2路归并),直到子序列中元素数为1,然后开始两两合并成有序的序列。基于这个想法引申到多路归并。

归并排序的过程:

初始序列:

申请临时数组:

开始递归:

递归ing

合并:

写回原数组:

合并-写回(两步)

合并

省略一步写回->合并两个子序列

合并:

对右边的序列执行上边的递归步骤...

最终写回原序列,完成排序:

显然归并使用的是分治的策略,从上边排序的过程可以看出来二路归并类似于一个后序遍历的过程,这样的话用树形表示会更直接一些:

递归过程:

开始合并:

右子树到了叶节点:

合并:

之后一直重复这个过程,知道回到根节点上。由此可以看出他的最坏时间复杂度是O(NlogN)。

源码:

void merge(int arr[], int tmp_arr[], int left_pos, int right_pos, int right_end)
{
	int i , left_end, num_count, tmp_pos;

	left_end = right_pos - 1;
	num_count = right_end - left_pos + 1;
	tmp_pos = left_pos;

	/*将两个要合并的序列,较小者先放入临时数组中*/
	while(left_pos <= left_end && right_pos <= right_end)
	{
		if(arr[left_pos] <= arr[right_pos])
		{
			tmp_arr[tmp_pos++] = arr[left_pos++];
		}
		else
		{
			tmp_arr[tmp_pos++] = arr[right_pos++];
		}
	}

	while(left_pos <= left_end)
	{
		tmp_arr[tmp_pos++] = arr[left_pos++];
	}
	while(right_pos <= right_end)
	{
		tmp_arr[tmp_pos++] = arr[right_pos++];
	}

	/*把临时数组中的数据copy回原数组*/
	for(i = 0; i < num_count; i++, right_end--)
	{
		arr[right_end] = tmp_arr[right_end];
	}
}
void msort(int arr[], int tmp_arr[], int left, int right)
{
	int center;
	if(left < right)
	{
		center = (left + right) / 2;
		msort(arr, tmp_arr, left, center);
		msort(arr, tmp_arr, center + 1, right);
		merge(arr, tmp_arr, left, center + 1, right);
	}
}
/*驱动函数*/
void merge_sort(int arr[], int count)
{
	int *tmp_arr;

	tmp_arr = (int *)malloc(count * sizeof(int));
	if(tmp_arr != NULL)
	{
		msort(arr, tmp_arr, 0, count-1);
		free(tmp_arr);
	}
	else
	{
		printf("error:alloc tempt array failed\n");
		return;
	}
}

将前几次排序使用的随机数文件拿过来测试了一下

10w数字时候排序的时间:

90w数字时候排序的时间:

时间: 2024-11-05 04:48:54

排序问题-归并排序的相关文章

排序问题之归并排序

排序问题 算法问题的基础问题之一,便是排序问题: 输入:n个数的一个序列,<a1, a2,..., an>. 输出:一个排列<a1',a2', ... , an'>,满足a1' ≤ a2' ≤... ≤ an' .(输出亦可为降序,左边给出的例子为升序) 一.算法描述 (1)分治法 归并排序是使用到了分治方法(Divide and Conquer). Divide:将原问题分解为若干子问题,其中这些子问题的规模小于原问题的规模. Conquer:递归地求解子问题,当子问题规模足够小

线程基础:多任务处理(13)——Fork/Join框架(解决排序问题)

============== 接上文< 线程基础:多任务处理(12)--Fork/Join框架(基本使用)> 3. 使用Fork/Join解决实际问题 之前文章讲解Fork/Join框架的基本使用时,所举的的例子是使用Fork/Join框架完成1-1000的整数累加.这个示例如果只是演示Fork/Join框架的使用,那还行,但这种例子和实际工作中所面对的问题还有一定差距.本篇文章我们使用Fork/Join框架解决一个实际问题,就是高效排序的问题. 3-1. 使用归并算法解决排序问题 排序问题是

疯狂的Java算法——插入排序,归并排序以及并行归并排序

从古至今的难题 在IT届有一道百算不厌其烦的题,俗称排序.不管是你参加BAT等高端笔试,亦或是藏匿于街头小巷的草根笔试,都会经常见到这样一道百年难得一解的问题. 今天LZ有幸与各位分享一下算法届的草根明星,排序届的领衔大神——插入排序以及归并排序.最后,在头脑风暴下,LZ又有幸认识了一位新朋友,名叫并行归并排序.接下来,咱们就一一认识一下,并且在最后来一次“算林大会”吧. 插入排序简介 插入排序,算林称最亲民的排序算法,插入排序采用最简单的插入方式对一个整数数组进行排序.它循环数组中从第二个开始

排序问题-快速排序

快速排序是在已知的排序算法中排序速度最快的,它的时间复杂度是O(NlogN),之所以特别快,只要是由于内部循环非常的精炼并且高度优化.和归并排序类似,快排也是基于分治的递归算法,将一个序列S快拍分为四步: 1.如果S中只有1个或者0个元素,则结束排序 2.在S中选取一个元素v作为快排使用的"枢轴": 3.将S中除去枢轴v的元素分成两个分别大于枢轴和小于数轴的不相交的序列: 4.分别对对小于和大于枢轴的序列进行上述的递归. 分析快排的四个步骤不难发现,一般的快排算法还有很多可以优化的地方

算法练习--归并排序、排列题

背景: 这几天玩的有点多了,代码敲少,今天补一发练习,顺便把前两天做的一个题也贴上. 正题: 1.归并排序 概念(来源百度百科):归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 我的理解,很简单,就是把一个无序数组进行分组,两两组作比较,组别的元素数目为 2^i(i=0,1,2,...,

#23 Merge k Sorted Lists (N路归并排序)

#23 Merge k Sorted Lists (N路归并排序) 题目地址:#23 题目分类:链表/归并排序/堆排序 题目难度:hard 题目 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 翻译:合并K个已经排序的链表,返回一个排序好的链表. 思路 暴力法,我们很容易想到:以一个for循环遍历所有的链表,找出最小的,然后将这个节点加入新的链表

分治归并排序

1 void Solution::devideConquerSort(vector<int>& vec) 2 { 3 int left = 0; 4 int right = vec.size() - 1; 5 mergeSort(vec, left, right); 6 } 7 8 void Solution::mergeSort(vector<int>& vec, int left, int right) 9 { 10 if(left < right) 11

算法与数据结构(2):时间复杂度——以归并排序为例

这一篇文章我们首先会介绍一下归并排序,并以归并排序和我们上一章所说的插入排序为例,介绍时间复杂度.此系列的所有代码均可在我的 github 上找到. 点此查看本文归并排序的完整代码. 分治法 在介绍归并排序前,我们需要首先介绍一下分治法,归并排序正是分治法的一个典型应用. 分治法:将原问题分解为多个规模较小的但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治法一般而言分为这三步: 分解:将原问题分为若干个子问题,这些子问题是原问题的规模较小的实例. 解

算法 排序NB二人组 堆排序 归并排序

参考博客:基于python的七种经典排序算法     常用排序算法总结(一) 序前传 - 树与二叉树 树是一种很常见的非线性的数据结构,称为树形结构,简称树.所谓数据结构就是一组数据的集合连同它们的储存关系和对它们的操作方法.树形结构就像自然界的一颗树的构造一样,有一个根和若干个树枝和树叶.根或主干是第一层的,从主干长出的分枝是第二层的,一层一层直到最后,末端的没有分支的结点叫做叶子,所以树形结构是一个层次结构.在<数据结构>中,则用人类的血统关系来命名,一个结点的分枝叫做该结点的"