基本排序之详解归并排序

                                 

                                                                       归并排序


一、归并排序的效率是仅次于快速排序的稳定的排序算法,其时间复杂度为O(nlog2n)。我们对n 个元素进行一次归并排序时,归并的次数约为log2n,每一次的两路归并排序元素的比较次数约为n-1。


二、归并排序的基本思想:

        归并排序是通过将一列数组序列中的元素看成一个一个的小序列来进行归并,直到所有的元素都被归并完成后,排序即完成,便是成功的完成了排序操作。


三、原理:

        如:我们对n 为9吧,这样更加好,如,a[9] = {1,2,5,4,3,8,6,7,9}这样的一个数组:

         原数组:

                      1       2      5     4      3      8     6    7     9

         第一次归并:

                     [1    2]    [4    5]    [3    8]    [6     7]     [9]

         第二次归并:

                     [1    2      4     5]      [3    6     7     8]     [9]

         第三次归并:

                   [1    2     3       4      5     6      7    8]     [9]   

         第四次归并:

                    [1    2     3       4      5     6      7    8      9]  

实现归并的操作代码:

			     for(i = L1,j = L2;i<=u1&&j <= u2;){ 
			         if(a[i] <= a[j]){
					        A->swap[pos] = a[i];
							i++;
						    pos++;
					   }else{
						    A->swap[pos] =  a[j];
						    j++;
						    pos++;				   
					   }
			     }
				
			   //此时我们要做的已经归并完成了
			   //此时我们要对在数组序列没有归并的进行归并
			   while(i <= u1 ){
			         A->swap[pos]=a[i];
					 i++;
					 pos++;
			   }
			   while(j <= u2 ){
			          A->swap[pos] = a[j];
					  j++;
					  pos++;
			   }
			   //此时对两个数组序列已经彻底归并完成了,而且此时是有序序列
			   //此时的L1 = u2+1了
			   L1 = u2 +1;
		//这里我们把只有一组的也存放到swap中
		for(int i = L1;i<length1;i++){
		       A->swap[i] = a[i];
		}


实现一次执行归并的核心代码:

/**
*归并排序的一次执行
*@param   int a[] 为接收的数组
*@param   int lenghth1 为此接收数组的长度
*@param   int swap[], 为保存执行完毕一次归并排序后的数组
*@param   int length2 为此归并好了的数组序列的长度
*@return  无
*/
void Merge(int a[],int length1 ,Array *A,int length2){
	    
	   //接收了数组我们需要对其进行归并和一次排序这时我们定义两个有指向的“指针”
	    int u1,u2;//此为这两个便于扫描的指针
	   //此时又需要定义两个数组序列的下界
		int L1,L2;
		//我们可以知道第一个数组序列的下界为0
		L1 = 0;
		//此时设置swap中的下标值pos来保存归并成功的数,因为pos是针对这整个循环的所以只能放在循环外面
	    int pos = 0;
		while(L1+length2<length1){
		       //我们可以得到第二个数组序列的下界了
		       L2 = L1 +length2;
	           //此时让u1,u2指向数组序列的上界
		       u1 =L2 -1;
	          //这时我们需要判断第二个数组序列是否越界,因为这时会出现最后一个数组序列不满length2这个值如[1 2 3  4][6]
		       if(L2 +length2-1< length1-1){
		               u2 = L2 +length2-1;
		       }else{
		               u2 = length1-1;
		       }
		     //现在我们把所有的指向问题都解决了,现在就需要进行扫描归并操作了
		     //此时对两个数组序列进行归并排序
		       int i,j;
			   i = L1,j = L2;
			   /**
			     *这里是方便的操作
			     *for(i = L1,j = L2;i<=u1&&j <= u2;){ 
			     *   if(a[i] <= a[j]){
				 *	        A->swap[pos] = a[i];
				 *			i++;
				 *		    pos++;
				 *	   }else{
				 *		    A->swap[pos] =  a[j];
				 *		    j++;
				 *		    pos++;				   
				 *	   }
				 * }
				 */
			   for(;;){
				   if(i<=u1&&j <= u2){
					   if(a[i] <= a[j]){
					        A->swap[pos] = a[i];
							i++;
							pos++;
					   }else{
						    A->swap[pos] =  a[j];
						    j++;
						    pos++;				   
					   }
				   }else{
				        break;
				   }
			   }
			   //此时我们要做的已经归并完成了
			   //此时我们要对在数组序列没有归并的进行归并
			   while(i <= u1 ){
			         A->swap[pos]=a[i];
					 i++;
					 pos++;
			   }
			   while(j <= u2 ){
			          A->swap[pos] = a[j];
					  j++;
					  pos++;
			   }
			   //此时对两个数组序列已经彻底归并完成了,而且此时是有序序列
			   //此时的L1 = u2+1了
			   L1 = u2 +1;
	    }

		//cout<<"L1"<<L1<<endl;
		//cout<<"lenght1"<<length1<<endl;
	    /*for(int i = 0;i <length1 ;i++){
		      cout<<"A->swap[i]......i="<<i<<"  "<<A->swap[i]<<endl;
		}*/
		//这里我们把只有一组的也存放到swap中
		for(int i = L1;i<length1;i++){
		       A->swap[i] = a[i];
		}
		//这样一次归并操作彻底完成了
		/*for(int i = 0;i <length1 ;i++){
		      cout<<"A->swap[i]......i="<<i<<"  "<<A->swap[i]<<endl;
		}
		cout<<"count....."<<count<<endl;*/
}
实现归并排序的代码段:

/**
*归并排序
*@param int a[]带归并的数组序列
*@param int length1 为带归并的数组序列的长度
*@return 无
*/
void Merge_sort(int a[],int length1){
	  //我们知道我们以数组长度为1开始归并
	  int length2 = 1;
	  //这里我们需要申请一个swap空间来作为交换的空间
	  Array *A =NULL;
	  if(A != NULL){
		  free(A);
	  }
	  A = (Array *)malloc(sizeof(Array )*length1);
	  if(A != NULL){
	       cout<<"申请空间成功!"<<endl;
	  }
	  while(length2 <length1){//直到归并完成Across跳出循环
	       Merge(a,length1,A,length2); 
		   for(int i = 0;i <length1;i++){
		         a[i]  = A->swap[i];//这里把归并后的数组序列再次保存回a[i]中
		   }
		   //这里需要更改归并后的新数组序列的长度
		   length2 = 2*length2;
	  }
	  //记住最后一定要对空间进行释放
	  free(A);
}
全部代码:

/**
*归并排序就是将一个数组分成若干个数组然后两两合并直到合并完成最后一个数组
*@author 菜鸟
*@version 2014.6.15
*/
#include <iostream>
#include <malloc.h>
#include <windows.h>
#define maxSize  100
using namespace std;
typedef int DataType;
typedef struct{
     DataType swap[maxSize];
}Array;
/**
*归并排序的一次执行
*@param   int a[] 为接收的数组
*@param   int lenghth1 为此接收数组的长度
*@param   int swap[], 为保存执行完毕一次归并排序后的数组
*@param   int length2 为此归并好了的数组序列的长度
*@return  无
*/
void Merge(int a[],int length1 ,Array *A,int length2){
	    
	   //接收了数组我们需要对其进行归并和一次排序这时我们定义两个有指向的“指针”
	    int u1,u2;//此为这两个便于扫描的指针
	   //此时又需要定义两个数组序列的下界
		int L1,L2;
		//我们可以知道第一个数组序列的下界为0
		L1 = 0;
		//此时设置swap中的下标值pos来保存归并成功的数,因为pos是针对这整个循环的所以只能放在循环外面
	    int pos = 0;
		while(L1+length2<length1){
		       //我们可以得到第二个数组序列的下界了
		       L2 = L1 +length2;
	           //此时让u1,u2指向数组序列的上界
		       u1 =L2 -1;
	          //这时我们需要判断第二个数组序列是否越界,因为这时会出现最后一个数组序列不满length2这个值如[1 2 3  4][6]
		       if(L2 +length2-1< length1-1){
		               u2 = L2 +length2-1;
		       }else{
		               u2 = length1-1;
		       }
		     //现在我们把所有的指向问题都解决了,现在就需要进行扫描归并操作了
		     //此时对两个数组序列进行归并排序
		       int i,j;
			   i = L1,j = L2;
			   /**
			     *这里是方便的操作
			     *for(i = L1,j = L2;i<=u1&&j <= u2;){ 
			     *   if(a[i] <= a[j]){
				 *	        A->swap[pos] = a[i];
				 *			i++;
				 *		    pos++;
				 *	   }else{
				 *		    A->swap[pos] =  a[j];
				 *		    j++;
				 *		    pos++;				   
				 *	   }
				 * }
				 */
			   for(;;){
				   if(i<=u1&&j <= u2){
					   if(a[i] <= a[j]){
					        A->swap[pos] = a[i];
							i++;
							pos++;
					   }else{
						    A->swap[pos] =  a[j];
						    j++;
						    pos++;				   
					   }
				   }else{
				        break;
				   }
			   }
			   //此时我们要做的已经归并完成了
			   //此时我们要对在数组序列没有归并的进行归并
			   while(i <= u1 ){
			         A->swap[pos]=a[i];
					 i++;
					 pos++;
			   }
			   while(j <= u2 ){
			          A->swap[pos] = a[j];
					  j++;
					  pos++;
			   }
			   //此时对两个数组序列已经彻底归并完成了,而且此时是有序序列
			   //此时的L1 = u2+1了
			   L1 = u2 +1;
	    }


		//cout<<"L1"<<L1<<endl;
		//cout<<"lenght1"<<length1<<endl;
	    /*for(int i = 0;i <length1 ;i++){
		      cout<<"A->swap[i]......i="<<i<<"  "<<A->swap[i]<<endl;
		}*/
		//这里我们把只有一组的也存放到swap中
		for(int i = L1;i<length1;i++){
		       A->swap[i] = a[i];
		}
		//这样一次归并操作彻底完成了
		/*for(int i = 0;i <length1 ;i++){
		      cout<<"A->swap[i]......i="<<i<<"  "<<A->swap[i]<<endl;
		}
		cout<<"count....."<<count<<endl;*/
}
/**
*归并排序
*@param int a[]带归并的数组序列
*@param int length1 为带归并的数组序列的长度
*@return 无
*/
void Merge_sort(int a[],int length1){
	  //我们知道我们以数组长度为1开始归并
	  int length2 = 1;
	  //这里我们需要申请一个swap空间来作为交换的空间
	  Array *A =NULL;
	  if(A != NULL){
		  free(A);
	  }
	  A = (Array *)malloc(sizeof(Array )*length1);
	  if(A != NULL){
	       cout<<"申请空间成功!"<<endl;
	  }
	  while(length2 <length1){//直到归并完成Across跳出循环
	       Merge(a,length1,A,length2); 
		   for(int i = 0;i <length1;i++){
		         a[i]  = A->swap[i];//这里把归并后的数组序列再次保存回a[i]中
		   }
		   //这里需要更改归并后的新数组序列的长度
		   length2 = 2*length2;
	  }
	  //记住最后一定要对空间进行释放
	  free(A);
}
/**
*这里需要一个输出函数,对数组序列进行输出out_put()
*@param int a[] 表示接受此数组的地址
*@param int length 表示此数组的长度
*@return 无
*/


void out_put(int a[],int length){
	for(int i = 0; i< length ;i++){
	        cout<<"第"<<i+1<<"个元素:"<<a[i]<<endl;
	}
	cout<<"输出完成!"<<endl;
}


int main(){
	  int a[10] = {1,2,5,4,3,8,6,7,9,0};
	  cout<<"未经排序的序列:"<<endl;
	  out_put(a,10);
	  Merge_sort(a,10);
	  cout<<"经归并排序后的序列:"<<endl;
	  out_put(a,10);
          system("PAUSE");
	  return 1;


}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值