排序算法(归并排序)

归并排序基本思想是:将已有序的子序合并,从而得到完全有序的序列,即先使每个子序有序,再使子序列段间有序。但归并的空间开销很大,要申请很多空间。

稳定性:稳定排序

时间复杂度:O(NlogN)

适用场景:一般运用在链表的排序中,因为其在链表的排序中就不用申请新的空间,可以通过断链在链接的方式实现。

如图

代码实现(递归)

实现步骤:

1、把区间分为两块,申请两块合适大小的动态数组,把分好的两块区间拷贝进申请的两个数组中;

2、对其分好块的进行递归。直到块的大小为2的时候开始进行比较

3、前块和后块都从第一个元素开始比较,按大小关系插入原数组中,插入的下标就往后移,为插入的就不动,与另一块的移动后的下标元素进行比较,若其中一块已经全部插入另一块中还有剩余,把剩余部分直接插入原数组。

template<class T>
void MergeSort(T *pData, size_t size, bool IsUp = true)
{
	if (size > 1)
	{
		int fsize, bsize;
		fsize = size / 2;
		bsize = size - fsize;
		T *pFrontData = new T[fsize];
		T *pBackData = new T[bsize];

		memcpy(pFrontData, pData, sizeof(T)*fsize);
		memcpy(pBackData, pData + fsize, sizeof(T)*bsize);

		MergeSort(pFrontData, fsize, IsUp);
		MergeSort(pBackData, bsize, IsUp);

		//归并流程
		int dataindex = 0;
		int findex = 0;
		int bindex = 0;

		if (IsUp)
		{
			while ((findex < fsize) && (bindex < bsize))
			{
				if (pFrontData[findex] < pBackData[bindex])
				{
					pData[dataindex] = pFrontData[findex];
					++dataindex;
					++findex;
				}
				else
				{
					pData[dataindex] = pBackData[bindex];
					++dataindex;
					++bindex;
				}
			}
		}
		else
		{
			while ((findex < fsize) && (bindex < bsize))
			{
				if (pFrontData[findex] > pBackData[bindex])
				{
					pData[dataindex] = pFrontData[findex];
					++dataindex;
					++findex;
				}
				else
				{
					pData[dataindex] = pBackData[bindex];
					++dataindex;
					++bindex;
				}
			}
		}

		while (findex < fsize)
		{
			pData[dataindex] = pFrontData[findex];
			++dataindex;
			++findex;
		}

		while (bindex < bsize)
		{
			pData[dataindex] = pBackData[bindex];
			++dataindex;
			++bindex;
		}
		SAFE_DELARR(pBackData);
		SAFE_DELARR(pFrontData);
	}
}

代码实现(非递归)

块的大小从2开始,不断往上乘2;直到块的大小超过元素大小的两倍,停止循环

申请的空间大小比递归的少,时间效率也比递归的高

template<class T>
void MergeSort2(T *pData, size_t size, bool IsUp = true)
{
	int blocksize = 2;
	int smallblocksize;
	int dataindex;
	int findex;
	int bindex;
	T *_pTempData = new T[size];  //创建一个用于合并原数据缓冲区,大小和原数据缓冲大小一致

	while (blocksize < (int)size * 2)  
		//块大小最大可以是接近整个数据的2倍
		//因为自下而上的流程并不一定blocksize*2会等于size,可以会比size小很多
		//所以要强制再扩大一次,只要不大于2倍大小都是可以的
	{
		smallblocksize = blocksize / 2;    //一个块就是叶节点的父亲节点
		//所以叶节点大小就为smallblocksize

		for (int blocks = 0; blocks < (int)size; blocks += blocksize)  //取每个大块的头
		{
			dataindex = blocks;
			findex = blocks;      //取每个大块的前小块的头
			bindex = blocks + smallblocksize;      //取每个大块的后小块的头

			//下面while循环为判定大块中的前后小块没有超出小块大小
			//并判断有没有超出所有元素的界限
			//_pTempData为合并的缓冲区
			//pData为原数据区
			while (((findex - blocks) < smallblocksize) &&
				(findex < (int)size) &&
				((bindex - (blocks + smallblocksize)) < smallblocksize) &&
				(bindex < (int)size))
			{
				if (pData[findex] < pData[bindex])
				{
					_pTempData[dataindex++] = pData[findex++];
				}
				else
				{
					_pTempData[dataindex++] = pData[bindex++];
				}
			}

			//同上,合并剩余的前小块
			while (((findex - blocks) < smallblocksize) &&
				(findex < (int)size))
			{
				_pTempData[dataindex++] = pData[findex++];
			}

			//同上,合并剩余的后小块
			while (((bindex - (blocks + smallblocksize)) < smallblocksize) &&
				(bindex < (int)size))
			{
				_pTempData[dataindex++] = pData[bindex++];
			}
		}

		//将合并好的缓冲区数据拷回原数据区
		memcpy(pData, _pTempData, sizeof(T)*size);
		blocksize *= 2;
	}

	SAFE_DELARR(_pTempData);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值