算法导论学习:归并排序法的实现

        上回学习了最简单也是最直接的插入排序。插入排序在小数据量时是很高效的,但是遇到大数据时,便显得无力了,今天来介绍归并排序,在大数据排序时,时间短,但同时它的空间使用率就显得高了。

第二章 算法基础

2.归并排序

        归并算法就是利用递归的特性,循环调用,递归求解。因采用分治算法的思想,对于大数据的排序处理效率很高。

        归并排序主要分为三个步骤:

        分解:把需要排序的数列分解为n/2个元素的两个子序列。

        解决:继续调用归并排序将两个子序列分别排序,直到分解为最后一个元素,即一个元素一定是排列好的。

        合并:把排列好的各个子序列合并起来,形成最终的排序。

        下面就是解决如何合并两个排列好的子序列的问题。合并两个子序列,用和之前一样的扑克牌的例子,其思想是:假设桌面上有两堆牌,面都是朝上的,每次从两个牌堆中最上面的两张牌中选取最小的,直到一堆牌选完为止,之后把另一堆牌直接放于排完的后面即可。为了代码的连续性与实现简单性,在每个牌堆中的最后加上一个无穷大的值(INF),没有会比无穷大的牌还大。《算法导论》中叫做哨兵牌。我觉得这是个很好的举措,简化了代码的实现过程。下面我先给出根据书中伪代码,以C实现的合并程序。

/************************************************************************
*  函数功能:合并两个排列好的数组                                       *
*  参数入口:Data为数组,p为第一个数组起点,q为终点,r为第二个数组终点  *
*  返回值:  无返回值                                                   *
************************************************************************/
void Merge(int *Data, int p, int q, int r)
{
	int n1=q-p+1;    //两个数组的长度
	int n2=r-q;
	int* L=(int*)malloc(sizeof(int)*(n1+1));       //申请两个长度为n1,n2的数组。
	int* R=(int*)malloc(sizeof(int)*(n2+1));
	for(int i=0;i<n1;i++)                 //将要合并的数组分别存入L,R中,并存入结束标志。
		L[i]=Data[p+i];
	for(int i=0;i<n2;i++) 
		R[i]=Data[q+1+i];
	L[n1]=INF;                  //结束标志。
	R[n2]=INF;
	for(int i=0,j=0,k=p;k<=r;k++)      //每次比较较小的值,将较小的值放于数组中。
	{                                  //等到一组没有后,结束值为INF,永远最大,因此,相当于直接将剩余的2值直接放于数组中。
		if(L[i]<=R[j])
		{
			Data[k]=L[i];
			i++;
		}
		else
		{
			Data[k]=R[j];
			j++;
		}
	}
	free(L);           //释放空间。
	free(R);
}

        下面就是完成分解程序,将一个数列,不断的分解为小数列,直到最后一个数列只有一个元素,即排列好的,之后调用合并程序,即可完成排序。

        下面给出分解程序:

/*************************************************
*  函数功能:归并排序                            *
*  参数入口:Data为数组,p为起点,r为终点        *
*  返回值:  无返回值                            *
**************************************************/
void Merge_sort(int *Data, int p, int r)
{
	if(p<r)
	{
		int q=(p+r)/2;
		Merge_sort(Data,p,q);
		Merge_sort(Data,q+1,r);
		Merge(Data,p,q,r);
	}
}
        分解程序中,不停的调用其本身,这样就可以分解到最后一个元素。在不断合并。下面给出整个实验程序:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ARRAY_LENGTH(array,len) {len=sizeof(array)/sizeof(array[0]);}    //宏定义获取数组长度的函数。
#define LENGTH 1000
#define INF 1000000

/************************************************************************
*  函数功能:合并两个排列好的数组                                       *
*  参数入口:Data为数组,p为第一个数组起点,q为终点,r为第二个数组终点  *
*  返回值:  无返回值                                                   *
************************************************************************/
void Merge(int *Data, int p, int q, int r)
{
	int n1=q-p+1;    //两个数组的长度
	int n2=r-q;
	int* L=(int*)malloc(sizeof(int)*(n1+1));       //申请两个长度为n1,n2的数组。
	int* R=(int*)malloc(sizeof(int)*(n2+1));
	for(int i=0;i<n1;i++)                 //将要合并的数组分别存入L,R中,并存入结束标志。
		L[i]=Data[p+i];
	for(int i=0;i<n2;i++) 
		R[i]=Data[q+1+i];
	L[n1]=INF;                  //结束标志。
	R[n2]=INF;
	for(int i=0,j=0,k=p;k<=r;k++)      //每次比较较小的值,将较小的值放于数组中。
	{                                  //等到一组没有后,结束值为INF,永远最大,因此,相当于直接将剩余的2值直接放于数组中。
		if(L[i]<=R[j])
		{
			Data[k]=L[i];
			i++;
		}
		else
		{
			Data[k]=R[j];
			j++;
		}
	}
	free(L);           //释放空间。
	free(R);
}

/*************************************************
*  函数功能:归并排序                            *
*  参数入口:Data为数组,p为起点,r为终点        *
*  返回值:  无返回值                            *
**************************************************/
void Merge_sort(int *Data, int p, int r)
{
	if(p<r)
	{
		int q=(p+r)/2;
		Merge_sort(Data,p,q);
		Merge_sort(Data,q+1,r);
		Merge(Data,p,q,r);
	}
}

/*************************测试main函数******************************/
int main(void)
{
	int* Data=(int*)malloc(sizeof(int)*LENGTH);
	srand((unsigned)time(NULL)); 
	for(int i=0;i<LENGTH;i++)                      //产生随机数
	{
		Data[i]=rand()%1000;          
	}
	for(int i=0;i<LENGTH;i++)                     
	{
		if(i%10==0)
			printf("\n");
		printf("%d  ",Data[i]);
	}
	Merge_sort(Data,0,LENGTH-1);
	for(int i=0;i<LENGTH;i++)                     
	{
		if(i%10==0)
			printf("\n");
		printf("%d  ",Data[i]);
	}

	return 0;
}
        归并算法的时间复杂度为O(nlgn),空间复杂度为O(n)。当数据量很大时,需要的堆栈深度要很大,因此,归并算法也有其局限性。今天就学习到这里吧。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值