归并排序的思想以及应用——试解《逆序对的数量》

一、前言

        您好,我是夏日弥,叫我“夏”或者“小弥”都可以。

        今天先来讲 归并排序 ——一种时间复杂度为 N●logN 的排序算法;

        让我们看看今天我们将要进入的主题吧!

二、归并排序

        2.1、概念&思想:

        归并排序是一种稳定的,时间复杂度为N●logN的排序算法,它由两个部分组成:

        递归划分(divide):将数组划分成左右两个部分,再将左右两个部分分别再划分成两个部分,以此类推,直至数组里的元素被划分成数个只有一个元素的数组;

        图解如下:(图丑莫见怪,小夏不会画画哈

 

我们把数组划分成这个样子后,递归合并回去;

         合并数组:数组元素较小的放在前面,数组元素较大的放在后面;

        图解如下:

 

        我们将两个小数组合并成一个局部有序的数组:

        以1248和3567为例:

 我们将 i 和 j 指向的那个较小数字拿出来放到 tmp[0] 里面:

 也就是拿出 1 放到 tmp[0] 里,随后我们移动指针 i 前进,tmp 的指针 t 前进;

 再比较2 和 3,把2 放进 tmp[1] 里,移动指针 i 和 t 前进;

 这次是3 和 4比较,把3放进去,移动指针 j 和 t前进;

   

 依次类推,直到 i 或 j 走到终点,再将剩余的数字全部复刻进tmp;

 

 

 1248 就是 12 和  48  以此种规则递归而来;3567依次类推;

        2.2、代码实现:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N],tmp[N];
unsigned int result;
void merge_sort(int a[],int l,int r){
	if( l >= r)return  ;//递归的排序的算法必须考虑到的,当数组只剩一个元素时就要返回单个元素了;
	int mid = (r + l )/2;//定义中点;
	merge_sort(a,l,mid);//递归前半部分;
	merge_sort(a,mid+1,r);//递归后半部分;
	
	
	
	/* 以下为缝合两个有序的数组的部分 */
	int i = l;//定义第一数组的前指针;
	int j = mid+1;//定义第二数组的前指针;
	int t = 0;//定义暂存数组的前指针; 
	while(i <= mid && j <= r ) //扫描第一数组和第二数组; 
	{
		if(a[i] <= a[j])
		{
			tmp[t++] = a[i++];//把较小的数字放入tmp数组中,再分别移动t针和i针; 
		}else{
			tmp[t++] = a[j++]; 
		}
	}
	 	/* 以下为补齐部分,将第一或者第二数组的剩余部分补齐进入tmp数组;*/
		while(i <= mid ){
			tmp[t++] = a[i++]; 
		}
		while(j <= r ){
			tmp[t++] = a[j++];
		}
		/* 以下为复制补全部分*/ 
		
	for(int i = l ,j = 0; i <= r ;i++,j++ ){
		a[i] = tmp[j];
	}/*为什么要从 i = l 开始?
	为什么是i针扫到r结束 ?
	*/ 
} 	
int main(){
	cin>>n;
	for(int i = 0;i<n;i++)cin>>a[i];
	merge_sort(a,0,n-1); 
	for(int i = 0 ;i<n;i++)cout<<a[i]<<" "; 
} 


 

经典的递归排序算法模板;

merge_sort (int a[],int l,int r) 
//第一个参数为需要排序的数组,第二个参数为排序起点,第三个参数为排序终点

 三、例题:

        3.1、归并排序:

        787. 归并排序 - AcWing题库

        使用上面的模板就可以AC了,更多是锻炼您对模板的记忆;

        3.2、活动 - AcWing

        唔....我们将利用递归思想分析这个问题:

        

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N],tmp[N];
unsigned int result =  0;
void merge_sort(int a[],int l,int r){
	if( l >= r)return  ;//递归的排序的算法必须考虑到的,当数组只剩一个元素时就要返回单个元素了;
	int mid = (r + l )/2;//定义中点;
	merge_sort(a,l,mid);//递归前半部分;
	merge_sort(a,mid+1,r);//递归后半部分;
	
	
	
	/* 以下为缝合两个有序的数组的部分 */
	int i = l;//定义第一数组的前指针;
	int j = mid+1;//定义第二数组的前指针;
	int t = 0;//定义暂存数组的前指针; 
	while(i <= mid && j <= r ) //扫描第一数组和第二数组; 
	{
		if(a[i] <= a[j])
		{
			tmp[t++] = a[i++];//把较小的数字放入tmp数组中,再分别移动t针和i针; 
		}else{

			tmp[t++] = a[j++];
 			result += (mid - i + 1);
		}
	}
	 	/* 以下为补齐部分,将第一或者第二数组的剩余部分补齐进入tmp数组;*/
		while(i <= mid ){
			tmp[t++] = a[i++]; 
		}
		while(j <= r ){
			tmp[t++] = a[j++];
			result += (mid-i+1);
		}
		/* 以下为复制补全部分*/ 
		
	for(int i = l ,j = 0; i <= r ;i++,j++ ){
		a[i] = tmp[j];
	}/*为什么要从 i = l 开始?
	为什么是i针扫到r结束 ?
	*/ 
} 	
int main(){
	cin>>n;
	for(int i = 0;i<n;i++)cin>>a[i];
	merge_sort(a,0,n-1);
	cout<<result;
} 


 

四、尾声

        感谢您的阅读和理解。

        小夏累了,下周以及下下周预计会比较忙,有不足之处还望您指出。

        特别鸣谢 lym 对本文的指导。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值