深入浅出之“归并算法”

1、概念
归并算法(操作、排序)是指将两个已经排序的序列合并成一个序列的操作

2、 用途
(1) 用合并算法将某个数组排序,步骤如下:
a、将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含2个元素;
b、 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含4个元素;
重复步骤2,直到所有元素排序完
(2) 用将两个有序子序合并成一个有序序列,并归操作步骤如下:
a、申请空间,大小为两个子序列之和,该空间用来存放合并后的序列;
b、设定两个指针,初始位置分别为两个已经排序序列的起始位置;
c、比较两指针所指元素,选相对小的元素放入到合并空间,并移动指针到下一个位置;
d、重复步骤3直到某一个指针达到序列尾;
e、将另一序列剩下的所有元素直接复制到合并序列尾

3、示例

(1)递归:

void mergeSort(int a,int b)// 下标,例如数组int is[5],全部排序的调用为mergeSort(0,4)   
{
	if(a<b)
	{
		int mid=(a+b)/2;
		mergeSort(a,mid);
		mergeSort(mid+1,b);
		merge(a,mid,b);
	}
}

void merge(int low,int mid,int high)
{
	int i=low,j=mid+1,k=low;
	while(i<=mid&&j<=high)
	{
		if(SrcArray[i]<=SrcArray[j])// 此处为稳定排序的关键,不能用小于
		{
			DstArray[k++]=SrcArray[i++];
		}
		else
		{
			DstArray[k++]=SrcArray[j++];
		}
	}

	while(i<=mid)
	{
		DstArray[k++]=SrcArray[i++];
	}

	while(j<=high)
	{
		DstArray[k++]=SrcArray[j++];
	}

	for(i=low;i<=high;i++)// 写回原数组
	{
		SrcArray[i]=DstArray[i];
	}
}

(2)非递归

// Merge.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>

#include <conio.h>

//函数原型
void ParallelSort(int szData[],int nLeftStartIndex,int nRightIndexStart,int nSubLen,int nTotalLen);

int main()
{
	//定义变量
	int a[]={1,5,3,6,7,4,2};
	int nTotalElemCounts=7;	// 排序元素个数
	int nSubOrderLen=1;	// 子序列长度初始值为

	//排序
	while( nSubOrderLen<nTotalElemCounts )  
	{
		int nTmpLeftStartIndex = 0;	// 左子序列起始地址,而nTmpLeftStartIndex+nLen 表示右子序列起始地址;
		int nTotalSubOrderCounts = nTotalElemCounts / nSubOrderLen; // 表示子序列个数
		for( int i=0;i < nTotalSubOrderCounts && nTmpLeftStartIndex < nTotalElemCounts;
			nTmpLeftStartIndex = ++i*nSubOrderLen*2 )
		{
			ParallelSort(a, nTmpLeftStartIndex, nTmpLeftStartIndex+nSubOrderLen, nSubOrderLen, nTotalElemCounts);
		}
		nSubOrderLen*=2; // 子序列的长度变成原来的倍
	}

	//输出排序后的元素
	for(int m=0;m<nTotalElemCounts;m++)
	{
		printf("%d\n",a[m]);
	}

	getch();
}

//为两个有序序列进行排序
void ParallelSort(int szData[],int nLeftStartIndex,int nRightStartIndex,int nSubLen,int nTotalLen)
{
	// 用于存放临时的数据
	int *szTempData = new int[nTotalLen];
	memset(szTempData, 0, nTotalLen);

	int flag=0;
	int i=0;
	int j=0;
	while(i<nSubLen && j<nSubLen 
		&& nLeftStartIndex+i<nTotalLen 
		&& nRightStartIndex+j<nTotalLen ) // 每次交换的次数有两个条件:步长数和最大长度;i管start1,j管start2
	{
		if(szData[nLeftStartIndex+i]<szData[nRightStartIndex+j])
		{
			szTempData[flag++]=szData[nLeftStartIndex+i];	
			++i;                  
		}
		else if(szData[nLeftStartIndex+i]==szData[nRightStartIndex+j])
		{
			szTempData[flag++]=szData[nLeftStartIndex+i];
			++i;
			++j;
		}
		else
		{
			szTempData[flag++]=szData[nRightStartIndex+j];
			++j;
		}
	}

	while(i<nSubLen && nLeftStartIndex+i<nTotalLen)
	{
		szTempData[flag++]=szData[nLeftStartIndex+i++];
	}

	while(j<nSubLen && nRightStartIndex+j<nTotalLen)
	{
		szTempData[flag++]=szData[nRightStartIndex+j++];
	}

	// 将有序序列覆盖到原数组
	for(i=nLeftStartIndex,j=0;i<nTotalLen && i<nLeftStartIndex+2*nSubLen;i++,j++)
	{
		szData[i]=szTempData[j];
	}

	delete [] szTempData;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值