手把手教你归并排序(非递归)

今天,我们一起来学习归并排序的非递归算法吧!

目录

一.优势

二.实现原理

三.代码实现


 

一.优势

       相比于递归算法,归并排序的非递归算法不用多次调用同一个函数,不会向递归算法一样因为函数嵌套调用次数太多而造成栈溢出。

二.实现原理

       其实,相比于递归的算法,非递归与之不同点就一个:在递归中我们通过递归到最底层(即两个数一组)进行排序,而非递归则是直接把数组分成两个数一组进行排序,这边排序完之后,再把数组分成四个一组排序,直到整个数组被分成两组,排序后就结束。

假设有一个数组:int a[6]

5 3 4 1 7 2

实现非递归的思路就是:先用一个参数记录5的下标,排序5和3后,参数跳到4,排序4和1,参数再跳到7,排序7和2。之后参数再到a[0]下标(参数=0),排序5、3、4、1,之后参数跳到7,排序7、2。最后,参数再到 a[0],排序整体即可。

由思路可知,我们想要单趟排序就要让参数从头开始跳,直到最后一个排序位置,这里可以用for循环来解决

以第一趟排序(两个一组)为例:

int gap = 1,gap是用来记录一组左右两边各几个,这里gap 是说一组里左右两边都是1个。

int head = 0, head来记录下标,因为归并排序每一组里又是分左和右的(参看递归算法的单趟排序原理手把手教你归并排序(递归))。

之后设int left1 = head, left2 = head + gap , right1 = head + gap - 1, right2 = left2 + gap - 1。然后像递归算法中单趟排序即可。

排完之后,head要到下一个位置,即head要到4所在的位置,排序方法同上。

排完4和3后head再加到7所在位置排序。这里排完之后就要结束for循环。所以head结束的标志是head = tail(数组最后一个元素下标) - gap - 1

所以for循环应该是:for(int head = 0; head < tail - gap; head += (gap* 2))

但这样只是一趟的,我们需要好多趟(两个一组、四个一组、八个一组...)所以for循环外要嵌套一个while循环,while循环是用来确定每一趟以几个为一组,可以理解为while循环用来改变gap的值的。每次for循环结束后gap *= 2即可。

大体框架如下:

int gap = 1; 

while(gap < tail)

{

        for(int head = 0; head < tail - gap; head += (gap*2))

                ........//for循环内容

        gap*=2;

}

三.代码实现

void mergesortnonr(int* a, int left, int right, int n)//归并排序非递归法
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i <= right; i = i + 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1, mid = i + gap - 1;
			int begin2 = mid + 1, end2 = i + 2 * gap - 1;
			int j = i;
			if (begin2 > right) break;
			if (end2 > right) end2 = right;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2]) tmp[j++] = a[begin1++];
				else tmp[j++] = a[begin2++];
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			for (int j = i; j <= end2; j++)
			{
				a[j] = tmp[j];
			}
		}
		gap = 2 * gap;
	}
}

创作不易,恳请点赞评论支持一下吧   如有错误,敬请斧正

 

 

你可能感兴趣的:(数据结构与算法,c++,算法,排序算法,归并排序,非递归算法)