非递归的归并排序

avatar
作者
猴君
阅读量:0

我们之前讲的快速排序有非递归的写法,那么归并排序也有非递归写法,我们一起来研究一下吧。

快速排序的非递归算法是使用的手动搭栈的方法,将区间存入栈里面,然后再排序,但是这次的归并排序可以吗?大家都知道归并排序是让左区间有序,右区间有序,然后再回到原来的区间使其有序,这个思路就类似于我们之前了解的后序一样,而快速排序就类似于中序,所以说,这次的归并排序就不能用搭栈的方法来实现非递归,那么,我们怎么实现呢?

思路,我们让这个数组先每个数一组,然后,使每一组都有序,然后,使每两组都有序,以此类推,我们就可以让整个数组有序。废话少说,大家看图:

相信我画的这幅图应该很清楚的表述了我的思路。

细节处理 

以上是大的思路,但是我们也有很多小细节也要处理好,否则千里之堤溃于蚁穴,前功尽弃。

区间处理

如上图所示,我们每次都会先分成两组,然后让他们有序,最好的方法就是设置两个区间,然后,再用变量控制这个区间,这是效率最高,又通俗易懂的方法,那么两个区间就是 

【begin1   end1】,【begin2   end2】;

设置一个i变量控制我们最左区间,设置一个gap等于我们每一组的数据个数,具体对应的样子上面的图也展示的很清楚,begin1就是i,然后其余的数就是根据这个gap来确定的,具体是什么样子请看下图:

这样安排数组就可以达到滚车轮的效果。

单数数组的越界 

我们先看一张图

这就很准确的表达了我们遇到的问题,万一给的数组不能双双配对怎么办?我们继续看后面 

上图是区间的变化图,显示的第一个越界是end2越界,第二个就是begin2和end2越界,所以说我们需要有针对这两种情况的处理办法,第一种,begin2和end2都越界,我们就抛弃他们,然后进入 下一个循环,第二种,end2越界,那么就让end2等于n-1。

代码展示

//非递归的归并排序 void MergeSortNonR(int* a, int* tmp,int n) { 	int gap = 1; 	while (gap < n) 	{ 		for (int i = 0; i < n;i += gap * 2) 		{ 			int begin1 = i; 			int end1 = i + gap - 1; 			int begin2 = i + gap; 			int end2 = i + gap * 2 - 1; 			if (begin2 >= n) 			{ 				break; 			} 			if (end2 >= n) 			{ 				end2 = n - 1; 			} 			int j = i;  			while (begin1 <= end1 && begin2 <= end2) 			{ 				if (a[begin1] < a[begin2]) 				{ 					tmp[j++] = a[begin1++]; 				} 				else 				{ 					tmp[j++] = a[begin2++]; 				} 			} 			//第一个数组没有全部进tmp数组 			while (begin1 <= end1) 			{ 				tmp[j++] = a[begin1++]; 			} 			//第二个没进 			while (begin2 <= end2) 			{ 				tmp[j++] = a[begin2++]; 			} 			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));  		} 		gap = gap * 2;  	}  }

大家可以试着自己调试一下。 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!