分治策略(归并排序)

【问题描述】将n个无大小顺序的数,按照大小排序。

【算法思想】将待排序元素分成大致相同的两组,分别对两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。

1、序列的合并

首先看,两个已序的序列的合并。举例,下面两个已序的序列:


先将两个已序的序列合并到另外一个序列里面


假设上述的序列都是在队列的结构中的话,要完成的过程就是先比较队列A和B队头的元素,如果A队头的元素比较小,那么就将A中队头元素取出,放入队列C中,这就完成了一次元素的转存;随后继续比较队列A和队列B队头的元素,将较小的元素存入序列C中,这样整个过程完成的时候C中就是一个排好序的元素序列了。

上述过程中,如果一共有N个元素,那么就进行了N次元素的比较操作。

将上述过程描述成程序如下:

//将序列1 src[0 ... mid] 和序列2 src[mid+1 ... right]
//两个序列归并到dst
template <class Type>
void Merge(Type src[], Type dst[], int left, int mid, int right)
{
	int l = left;      //指向序列1
	int r = mid + 1;   //指向序列2
	int dt = left;     //指向目的序列
	while(l <= mid && r <= right)  //如果两个序列都没有到头
	{
		if(src[l] < src[r])        //如果序列1中的值较小,将序列1中的值写到目标序列中
			dst[dt++] = src[l++];  //序列1索引往后移动,目标序列索引往后移动
		else	                   //如果序列2中的值较小,将序列2中的值写到目标序列中
			dst[dt++] = src[r++];  //序列2索引往后移动,目标序列索引往后移动
	}
	
	if(l > mid)                    		//如果序列2还没有读完
	{
			for(int i=r; i<=right; ++i)
			dst[dt++] = src[i];    		//依次读入剩下的序列
	}
	else                           		//如果序列1还没有读完
	{
			for(int i=l; i<=mid; ++i)   //依次读入剩下的序列
			dst[dt++] = src[i];
	
	}
}

2、递归实现归并排序

  对于一个随机的未排序的序列来说。如果序列长度是1,显然就不需要排序。否则,可以递归地将前半部分和后半部分序列进行归并排序(不仅仅是合并!)

程序描述如下:

template <class Type>
void MergeSort(Type a[],int left,int right)
{
	if (left < right)   //序列中不止有一个元素
	{
		int i = (left + right) / 2;
		MergeSort(a,left,i);      //对左侧归并排序
		MergeSort(a,i+1,right);   //对右侧归并排序
		Merge(a,b,left,i,right);  //合并左右序列
		for(int k=left; k<=right; k++)  
		{  
			a[k] = b[k];  
		}  
	}
}


3、举例

#include <iostream>
using namespace std;

int a[11] = {9,8,4,65,21,31,6,17,101,11,52};
int b[11];

//完成序列的合并
//原序列src[left ... middle] src[middle+1 ... middle]合并到dst[]中
template <class Type>
void Merge(Type src[],Type dst[],int left,int middle,int right)
{
	int l = left;           //指向序列src[left ... middle]待取出的首元素位置
   	int r = middle+1;       //指向序列src[middle+1 ... right]待取出的首元素位置
	int dt = left;          //指向目标序列dst待存入的首元素位置
	//若src[left ... middle] 和 src[middle+1 ... right]中元素均未取完
	while ((l <= middle) && (r <= right))
	{
		if (src[l] < src[r])
			dst[dt++] = src[l++];
		else
			dst[dt++] = src[r++];
	}

	if (l > middle)//src[left ... middle]序列内容取完了,将剩余src[middle+1 ... right]依次填入
	{
		for (int i = r;i <= right;i++)
		{
			dst[dt++] = src[i];
		}
	}
	else           //src[middle+1 ... right]序列内容取完了,将剩余src[left ... middle]依次填入
	{
		for (int i = l;i <= middle;i++)
		{
			dst[dt++] = src[i];
		}
	}
}


template <class Type>
void MergeSort(Type a[],int left,int right)
{
	if (left < right)
	{
		int i = (left + right) / 2;
		MergeSort(a, left, i);
		MergeSort(a, i+1, right);
		Merge(a, b, left, i, right);
		for(int k = left; k <= right; k++)  
		{  
			a[k] = b[k];  
		}  
	}
}


int main()
{
	for(int i=0; i<11; i++)  
	{  
		cout<<a[i]<<" ";  
	}  
	cout<<endl;  
	MergeSort(a,0,10);  
	for(int i=0; i<11; i++)  
	{  
		cout<<a[i]<<" ";  
	}  
	cout<<endl;
	system("pause");
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空空的司马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值