您的位置:首页 > 其它

SHUOJ——归并排序——计算思维J题

2015-09-02 13:04 288 查看

归并排序(Mergesort)

归并排序以O(NlogN)的复杂度运行,是使用比较次数最优解以及基于递归算法的很好的实例。

算法原理:
算法的基本操作是合并两个已经排序的表,然后按顺序将两个表中的元素进行比较厚放入第三个表中。 基本的合并算法是取两个输入数组A和B,一个输出数组C,以及三个指针pA,pB,pC. 他们都始于对应数组的开始端。 A[pA]和B[pb]中的较小者放入C的下一个位置,pc以及较小者的指针向前推进一格。 当有其中一格输入表输完时,则将另外一个输入表剩余元素输入到输出表的位置中。
显然,合并两个已经排序的表是线性的,因为最多只能进行N-1次比较(N为元素总数)。 注意点:每次比较都只放一个元素,但最后一次比较完是放两个元素
因此归并排序很容易描述为递归操作。如果N=1 ,则只需要一格元素排序,否则,就以递归的方式将前半部分和后半部分各自排序。

复杂度分析:
我们以N=1时的操作数视为常数1,并且假定N为2的幂整数。那么我们总能将N分成均为偶数的两个部分。另外,对N个数排序的用时等于完成两个大小为N/2的递归排序所用的时间再加上合并的时间(即当前元素总数)
那么我们可以得到:
T(1)=1
T(N)=2T(N/2)+N
我们在2式两边除以N 则能得 T(N)/N=T (N/2)/ N/2 + 1

同样的,因为N是2的幂整数,我们可以将N一直往下除2变成:

T(N)=2T(N/2)+N

T(N/2) / N/2 = T( N/ 4) / N/4 + 1

T( N/4) / N/4 =T (N/8) / N/8 + 1

………………

T(2)/ 2 = T(1) / 1 +1

我们将上式相加,左右相同元素消去,最终得到:

T(N) / N = T(1 ) /1 +log N

最终得到 T(N)= N log N +N = O(N log N)

现在贴例题: http://202.121.199.212/JudgeOnline/problem.php?cid=1130&pid=9

Description

Sort公司是一个专门为人们提供排序服务的公司,该公司的宗旨是:“顺序是最美丽的”。他们的工作是通过一系列移动,将某些物品按顺序摆好。他们的服务是通过工作量来计算的,即移动东西的次数。所以,在工作前必须先考察工作量,以便向用户提出收费数目。

假设我们将序列中第i件物品的参数定义为Ai,那么,排序就是指将A数组从小到大排序。用户并不需要知道精确的移动次数,实质上,大多数人都是凭感觉来认定这一列物品的混乱程度,根据Sort公司的经验,人们一般是根据“逆序对”的数目多少来称呼这一序列的混乱程度。

若数组A的元素A1,…,An互不相同,所谓数组A的“逆序对”是指,若i<j且Ai>Aj,则<i,j>就为一个“逆序对”。请你为Sort公司做一个程序,在尽量短的时间内,统计出"逆序对"的数目。

Input

输入有若干行,每两行对应一种情形。两行中的第一行为一个整数n(1≤n≤1000),接下来一行为n个互不相同的整数。

输入直到文件输入结束。

Output

对每一种情形的测试数据,在一行上先输出“Case #:”,其中“#”是测试数据集的编号(从1开始),接着在下面的输出结果。

Sample Input

5

3 1 4 5 2

6

1 2 3 4 5 6

7

7 6 5 4 3 2 1


Sample Output

Case 1:

4

Case 2

:0

Case 3:

21


题目思路 : 通过归并算法,以分支 递归 将数组分为前后两个部分, 当前半部分数组元素大于后半部分数组元素时,则说明需要进行比较的替换,

其比较次数 ans =m -i +1 (其中 m为数组中间位置, i为前半部分数组需要进行交换的元素的位置, ans原理不证)

贴代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#ifndef _SHUOJ_J_
#define _SHUOJ_J_

using namespace std;
const int Maxn = 1005;

int a[Maxn],tmp[Maxn];
int ans;

void Merge(int l,int m,int r)
{
int i = l;
int j = m + 1;
int k = l;
while(i <= m && j <= r)
{
if(a[i] > a[j])        //进行比较
{
tmp[k++] = a[j++]; //大于则说明需要交换
ans += m - i + 1;
}
else
{
tmp[k++] = a[i++]; //小于直接放入输出数组
}
}
while(i <= m) tmp[k++] = a[i++]; //此时有一表已经输完,将剩余元素放入表中
while(j <= r) tmp[k++] = a[j++];
for(int i=l;i<=r;i++)
a[i] = tmp[i];     //将排序好的数组放入
}

void Merge_sort(int l,int r)
{
if(l < r)
{
int m = (l + r) >> 1;
Merge_sort(l,m);
Merge_sort(m+1,r);
Merge(l,m,r);
}
}

int main()
{
int n,tt=1;
int cas=0;
while(cin>>n)
{
cas++;
for(int i=0;i<n;i++)
cin>>a[i];
ans = 0;
Merge_sort(0,n-1);
printf("Case %d:\n",cas);
cout<<ans<<endl;
}
return 0;
}

#endif  //SHUOJ_J_
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: