【算法总结】归并排序总结

【前言】

归并排序的思想是,将一个数组划分成为可以轻易排序的最小部分(最小部分的标准通常是1个数或者两个数),对最小数组排好序后,向上合并排序数组(向上合并排序通常需要额外空间,譬如:现在两个排好序的部分:7,12和5,15,我们将它们合并成为5,7,12,15---存储在临时区,然后再放回原本数组里面,然后将这部分作为合并的部分再向上递归合并)。核心思想便是如此。当然,在用代码实现的时候会出现种种问题,譬如:合并的时候越界了,合并结果不对等等,这些只要细心调试即可解决。

下面用例子及图片来说明这个算法,顺便将java版的归并排序贴出来:


【这里参考:递归算法学习系列二(归并排序)

      归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为:

      1)划分子表

      2)合并半子表 

     首先我们来讨论归并算法,归并算法将一系列数据放到一个向量中,索引范围为[first,last],这个序列由两个排好序的子表构成,以索引终点(mid)为分界线,以下面一个序列为例

    7,10,19,25,12,17,21,30,48

   这样的一个序列中,分为两个子序列 7,10,19,25  和 12,17,21,30,48,如下图所示:

   image 

再使用归并算法的时候的步骤如下:

 第一步:比较v[indexA]=7和v[indexB]=12,将较小的v[indexA]取出来放到临时向量tempArray中,然后indexA加1

  image

 

 第二步:比较v[indexA]=10和v[indexB]=12,将较小的10放到临时变量tempArray中,然后indexA++;

  image

第三步:比较v[indexA]=19与v[indexB]=12,将较小的12存放到临时变量tempArray中,然后indexB++;

   image

第四步到第七步:按照以上规则,进行比对和存储,得到如下结果:

   image

最后一步:将子表b中剩余项添加到临时向量tempArray中

   image 

然后将临时变量中的值按照索引位置,拷贝回向量v中,就完成了对向量v的归并排序



【下面就是不才编写的代码实现了,仅供参考】

package MergeSort;

public class MergeSortMain {
	
	public static void main(String[] args){
		int[] theArr=new int[]{98,75,14,15,18,12,14,16,77,1,99,47};
	 MergeSortMain mysort=	new  MergeSortMain(theArr);
		mysort.megerSort();
		mysort.debugPrint();
		
		
	}
	
	private int[] _tmpArr;//--临时区域,为了避免操作原始数组导致结构变化,所以这里直接copy一个数组,然后操作这个数组。
	private int[] _middle_result;
	private int[] _originArr;
	public MergeSortMain(int[] needSortedArray){
		if(needSortedArray==null){
			return;
		}
		_originArr=needSortedArray;
		_tmpArr=new int[needSortedArray.length];
		_middle_result=new int[needSortedArray.length];
		int cindex=0;
		for(int i:_originArr){
			_tmpArr[cindex]=i;
			cindex++;
		}
		
	}
	
	public int[] megerSort(){
		if(_tmpArr==null||_tmpArr.length<=1){
			return _tmpArr;
		}
		if(_tmpArr.length==2){
			recursion_division(0, 1);
			return _tmpArr;
		}
		else{
			 
			 recursion_division(0, _tmpArr.length-1);
			 return _tmpArr;
		}
		
		
	}
	/**
	 * 递归处理归并排序。
	 * beginLoc===表示当前归并排序的左界,
	 * endloc表示右界,当左界=右界时,表示当前划分出来的是一个数,不用排序了。
	 * */
	private void recursion_division(int beginLoc,int endLoc){
		if(beginLoc>=endLoc){
			return;
		}
		else if(endLoc-1==beginLoc){
			meger_sort_division(beginLoc, beginLoc, endLoc, endLoc);
			return;		
			
		}
		int tmpLoc1=  (int)Math.floor(((double)((beginLoc+endLoc)/2)));
		recursion_division(beginLoc, tmpLoc1);
		recursion_division(tmpLoc1+1, endLoc);
		meger_sort_division(beginLoc, tmpLoc1, tmpLoc1+1, endLoc);
		
	}
	
	private void meger_sort_division(int beginLoc1,int endLoc1,int beginLoc2,int endLoc2){
		
		if(beginLoc1<=endLoc1&&beginLoc1<=endLoc2&&beginLoc1<beginLoc2){
			if(beginLoc1==endLoc1&&beginLoc2==endLoc2){
				if(_tmpArr[beginLoc1]>_tmpArr[beginLoc2]){
					int itmp=_tmpArr[beginLoc1];
					_tmpArr[beginLoc1]=_tmpArr[beginLoc2];
					_tmpArr[beginLoc2]=itmp;
				}
				debugPrint();
				return;
			}
			else{
				
				int theLength=endLoc2-beginLoc1+1;
				
				int leftLoc=0;
				int rightLoc=0;
				int theCindex=0;
				for(int cindex=0;cindex<theLength;cindex++){
					
					if(beginLoc1+leftLoc>endLoc1||beginLoc2+rightLoc>endLoc2){
					
						break;
					}
					
					if(_tmpArr[beginLoc1+leftLoc]<=_tmpArr[beginLoc2+rightLoc]){
						_middle_result[cindex]=_tmpArr[beginLoc1+leftLoc];
						leftLoc++;
						theCindex=cindex;
						continue;
					}
					else if(_tmpArr[beginLoc1+leftLoc]>_tmpArr[beginLoc2+rightLoc]){
						_middle_result[cindex]=_tmpArr[beginLoc2+rightLoc];
						rightLoc++;
						theCindex=cindex;
						continue;
					}
					
					
				}
				/**
				 * 假如这个,表明出现了左边遍历完,右边没有遍历完;或者右边遍历完,左边没有遍历完的情况。
				 * */
				if(theCindex<theLength-1){
					if(beginLoc1+leftLoc<=endLoc1){
						for(int cindex=beginLoc1+leftLoc;cindex<=endLoc1;cindex++){
							_middle_result[theCindex+1]=_tmpArr[cindex];
							theCindex++;
						}

					}
					else if(beginLoc2+rightLoc<=endLoc2){
						for(int cindex=beginLoc2+rightLoc;cindex<=endLoc2;cindex++){
							_middle_result[theCindex+1]=_tmpArr[cindex];
							theCindex++;
						}
					}
				}
				
				/**
				 * 将结果放回排序数组中。
				 * */
				for(int cindex=0;cindex<theLength;cindex++){
					_tmpArr[beginLoc1+cindex]=_middle_result[cindex];
				}
				
				debugPrint();
				
			}
		}
		else{
			return;
		}
		
	}
	
	public void debugPrint(){
		if(_tmpArr==null){
			return;
		}
		System.out.println("");
		System.out.print("合并结果:");
		for(int i:_tmpArr){
			
			System.out.print("  "+i+" ");
		}
	}
	
	

}

运行结果如下:

合并结果:  75   98   14   15   18   12   14   16   77   1   99   47 
合并结果:  14   75   98   15   18   12   14   16   77   1   99   47 
合并结果:  14   75   98   15   18   12   14   16   77   1   99   47 
合并结果:  14   75   98   12   15   18   14   16   77   1   99   47 
合并结果:  12   14   15   18   75   98   14   16   77   1   99   47 
合并结果:  12   14   15   18   75   98   14   16   77   1   99   47 
合并结果:  12   14   15   18   75   98   14   16   77   1   99   47 
合并结果:  12   14   15   18   75   98   14   16   77   1   99   47 
合并结果:  12   14   15   18   75   98   14   16   77   1   47   99 
合并结果:  12   14   15   18   75   98   1   14   16   47   77   99 
合并结果:  1   12   14   14   15   16   18   47   75   77   98   99 
合并结果:  1   12   14   14   15   16   18   47   75   77   98   99 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值