博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
模板:排序(四)
阅读量:6676 次
发布时间:2019-06-25

本文共 2996 字,大约阅读时间需要 9 分钟。

归并排序

“然而,”路由器说道,“快排的魔法是不稳定的……你的代码最终没有通过啊怎么办?”

“啊?那那……”勇者支支吾吾。
于是,他们只好造访了照相馆,借来了一本魔法书,但是魔法书经过风吹日晒所以代码丢失了,不过他的解释步骤还是很明显的。
“……那么想必看到这里的魔法师一定都会了神奇的桶排序了,我们可以借用这个思想来解释下接下来要讲的魔法……”
“归并排序,O(NlogN)”
“我们首先将整个数据分成两半,将每一半放在一个桶里面,然后对产生的新桶重复这个动作,一直到无法继续分下去(也就是桶里只剩下了一个元素为止)。”
“之后就是惊心动魄的排序环节了。我们将每一个从一个桶里面分裂出来的两个桶称作同类,此时我们所需要做的,就是将同类桶进行排序,合并成原先分裂的桶,然后继续将同类桶排序……”
“恩,没了……”路由器指了一下残叶,“来吧,我们来写代码吧……”
代码如下:

#include
#include
#include
#include
#include
using namespace std;int n,a[1000111],t[1000111];void msort(int x,int y){ if(x==y) return; int mid=(x+y)/2; msort(x,mid); msort(mid+1,y); int l=x,r=mid+1,j=x;//l左指针,r右指针,j当前数位 while(l<=mid&&r<=y)//比较,落下小的 { if(a[l]<=a[r]){ t[j]=a[l];l++;j++;//左指针++,当前数位++ } else{ t[j]=a[r];r++;j++;//右指针++,当前数位++ } } while(l<=mid){
//将剩余没落下的数字按顺序落下 t[j]=a[l];l++;j++; } while(r<=y){ t[j]=a[r];r++;j++; } for(int i=x;i<=y;i++)a[i]=t[i];//更新数组为排序后的数组 }int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } msort(1,n); for(int i=1;i<=n;i++){ printf("%d ",a[i]); } return 0;}

逆序对问题

“然而,这个魔法的作用却不只是排序,因为排序大部分情况下都是sort,所以我们可以用来解决……”

“逆序对问题”

(OpenJudge 7622)

总时间限制:
1000ms

内存限制:

65536kB
描述
在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。

输入

第一行是一个整数n,表示该排列有n个数(n <= 100000)。
第二行是n个不同的正整数,之间以空格隔开,表示该排列。
输出
输出该排列的逆序数。
样例输入
6
2 6 3 4 5 1
样例输出
8

提示:

1.利用二分归并排序算法(分治);
2.注意结果可能超过int的范围,需要用long long存储。

好的,为什么说归并排序可以解决这个问题呢?还记得归并排序的原理吗?实际上,归并排序已经将所有的区间都给我们划分好了,所以我们只需要求出每个区间的逆序对有几个就可以了。

而且归并排序因为每归并一次都会排好序,所以我们的计算也可以变得更加简单(详情看注释)。

那么附上代码吧,也没什么好讲的:

#include
#include
#include
#include
#include
using namespace std;int n,a[1000111],t[1000111];long long ans = 0;void msort(int x,int y){ if(x==y) return; int mid = (x + y) /2; msort(x,mid); msort(mid+1,y); int l = x, r = mid+1, j = x; while(l<=mid && r<=y) { if(a[l]<=a[r]){ t[j] = a[l]; j++;l++; } else{ t[j] = a[r]; r++;j++; ans += mid-l+1;//在l与mid区间里面每一个数对于r来说都是它的逆序对 } } while(l<=mid){ t[j] = a[l]; j++;l++; } while(r<=y){ t[j] = a[r]; r++;j++; } for(int i=x;i<=y;i++)a[i] = t[i];}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } msort(1,n); printf("%lld",ans); return 0;}

转载于:https://www.cnblogs.com/luyouqi233/p/7706041.html

你可能感兴趣的文章
常用数据结构及复杂度
查看>>
poj3278 Catch That Cow
查看>>
IDEA调试方法总结及各种Step的区别
查看>>
简易图片轮播效果
查看>>
Spring Boot 数据库连接池 Druid
查看>>
Android学习笔记(十)——ListView的使用(上)
查看>>
NodeList对象的特点
查看>>
【转载】【原创】生命中,要有自己的一方晴天
查看>>
JQuery操作CheckBox和Radio
查看>>
快速求幂
查看>>
gulp初学
查看>>
JS设置localStorage有效期
查看>>
Ajax常用写法
查看>>
测试用例设计-WEB通用测试用例
查看>>
53、listview、expandableListview如何选中时保持高亮?
查看>>
js中将数字和字符串相互转换的方法(转自脚本之家www.jb51.net)
查看>>
centos6.5-VMware虚拟机-双网卡绑定
查看>>
scala言语基础学习二
查看>>
《团队-科学计算器-项目总结》
查看>>
理解单例模式
查看>>