[算法竞赛进阶指南] 超快速排序 (归并排序+逆序对)

本文介绍了一种特殊的排序算法——超快速排序,并通过分析其特性,利用归并排序求解逆序对的方法,有效地计算了排序过程中所需的最小交换次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

在这个问题中,您必须分析特定的排序算法----超快速排序。

该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序。

对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 5 9。

您的任务是确定超快速排序需要执行多少交换操作才能对给定的输入序列进行排序。

输入格式

输入包括一些测试用例。

每个测试用例的第一行输入整数n,代表该用例中输入序列的长度。

接下来n行每行输入一个整数ai,代表用例中输入序列的具体数据,第i行的数据代表序列中第i个数。

当输入用例中包含的输入序列长度为0时,输入终止,该序列无需处理。

输出格式

对于每个需要处理的输入序列,输出一个整数op,代表对给定输入序列进行排序所需的最小交换操作数,每个整数占一行。

数据范围

0≤N<500000
0≤ai≤999999999

输入样例

5
9 1 0 5 4
3
1 2 3
0

输出样例

6
0

分析:
  • 归并排序求逆序对

  • 第一眼看这个题,发现它就是模仿冒泡排序,假如相邻两个后面一个大于前面一个就交换他们的位置,并且次数减一。但是一看数据量,发现O(n^2)的代码根本不可能通过.

  • 仔细细想交换的次数不就是逆序对数,因为一个数后面有几个比他小的他就会交换几次,所以我们求出逆序对数就好了,而求逆序对数,我们可以使用归并来求,归并排序中当合并的时候,假如后面一个数组的数小的时候我们就可以知道 ,前面一个数组剩下的全部都比他大,所以

    ans+=mid-l+1;
    

具体实现如下。

代码
#include <iostream>
using namespace std;
typedef long long ll;
#define filr(i,a,b) for(i=a;i<=b;i++)
ll n,arr[500005],temp[500005],i,ans;

void merger_sort(ll l,ll r){
	if(r<=l) return ;
	ll mid=(l+r)>>1;
	merger_sort(l,mid);
	merger_sort(mid+1,r);
	ll k=mid+1,t=l,x=l;
	while(x<=mid||k<=r){
		if(k>r||(x<=mid&&arr[x]<=arr[k])){
			temp[t++]=arr[x++];
		}else{
			temp[t++]=arr[k++];
			ans+=mid-x+1;
		}
	} 
	filr(i,l,r) arr[i]=temp[i];
}

int main()
{
	while(cin>>n&&n){
		ans=0;
		filr(i,1,n) cin>>arr[i];
		merger_sort(1,n);
		cout<<ans<<endl;
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值