归并排序求逆序数(排序算法)

归并排序:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。——(摘自百度百科)

具体操作:

比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

在这里先讲一下 如果有两个数组是有序的话,那么我们怎么进行排序呢,肯定是两个指针i,j每次后移,判断的时候就是这样:

#include <iostream>
#include <cstdio>
using namespace std;
int a[15],b[15],c[15];
void Merge_Sort(int n, int m)///n是数组a的长度,m是数组b的长度
{
    int i, j, k;
    i = j = k = 0;
    while(i<n && j<m)
    {
        if(a[i] < b[j])///因为是已经排好序的只要a[i]比b[j]小i就后移
            c[k++] = a[i++];
        else///同理
            c[k++] = b[j++];
    }
    while(i < n)///这个是b数组已经全部比完
        c[k++] = a[i++];
    while(j < m)///这个是a数组已经全部比完
        c[k++] = b[j++];
}
int main()
{
    int n, m;
    while(cin>>n>>m)
    {
        for(int i=0; i<n; i++)
            cin>>a[i];
        for(int i=0; i<m; i++)
            cin>>b[i];
        Merge_Sort(n, m);
        for(int i=0; i<n+m; i++)
            cout<<c[i]<<" ";
    }
    return 0;
}

其实归并排序就是跟上面一样的,只不过呢,我们要做的是将两个两个数组进行排序,给一组样例:

6 2 7 5 3 1 4

第一步:(6,2) (7,5) (3,1) (4)

两两排序(2,6)(5,7)(1,3)(4)

第二步:{(2,6),(5,7)}{(1,3),(4)}

两两排序(2,5,6,7) (1,3,4)

第三步:{(2,5,6,7),(1,3,4)}

两两排序 1 2 3 4 5 6 7

其实我们就是先用递归算法将这 n 个数分解成一个一个的数,因为这样是已经排好序的,然后我们在两两进行合并,接下来给一个归并排序求逆序数的代码:

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 50000+5;
int cnt = 0;
int a[MAXN],p[MAXN];
void Merge_Array(int first, int mid, int last)
{
    int i=first, j=mid+1, k=first;
    while(i<=mid && j<=last)
    {
        if(a[i] <= a[j])
            p[k++] = a[i++];
        else
        {
            p[k++] = a[j++];
            cnt += j-k;
        }
    }
    while(i <= mid)
        p[k++] = a[i++];
    while(j <= last)
        p[k++] = a[j++];
    for(int i=first; i<=last; i++)
        a[i] = p[i];
}
void Merge_Sort(int first, int last)
{
    if(first < last)
    {
        int mid = (first + last) >> 1;
        Merge_Sort(first, mid);
        Merge_Sort(mid+1, last);
        Merge_Array(first, mid, last);
    }
}
int Scan()///输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())==‘-‘)
        flag=1;
    else if(ch>=‘0‘&&ch<=‘9‘)
        res=ch-‘0‘;
    while((ch=getchar())>=‘0‘&&ch<=‘9‘)
        res=res*10+ch-‘0‘;
    return flag?-res:res;
}

void Out(int a)///输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+‘0‘);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        cnt = 0;
        for(int i=0; i<n; i++)
            a[i] = Scan();
        Merge_Sort(0, n-1);
        Out(cnt);
        puts("");
    }
    return 0;
}
时间: 2025-01-11 02:58:17

归并排序求逆序数(排序算法)的相关文章

POJ训练计划2299_Ultra-QuickSort(归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 39279   Accepted: 14163 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

hiho一下 第三十九周 归并排序求逆序数

题目链接:http://hihocoder.com/contest/hiho39/problem/1 ,归并排序求逆序数. 其实这道题也是可以用树状数组来做的,不过数据都比较大,所以要离散化预处理一下,文中也会给出离散化+树状数组的解法,不过要比归并排序慢一点. 算法: 还是按照题中给的解法. 我们来看一个归并排序的过程: 给定的数组为[2, 4, 5, 3, 1],二分后的数组分别为[2, 4, 5], [1, 3],假设我们已经完成了子过程,现在进行到该数组的“并”操作: a: [2, 4,

poj 2299 Ultra-QuickSort 归并排序求逆序数对

题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题思路: 根据冒泡排序的特点,我们可知,本题只需要统计每一个数的逆序数(如果有i<j,存在a[i] > a[j],则称a[i]与 a[j]为逆序数对),输出所有的数的逆序数的和用普通排序一定会超时,但是比较快的排序,像快排又无法统计 交换次数,这里就很好地体现了归并排序的优点.典型的利用归并排序求逆

poj2299解题报告(归并排序求逆序数)

POJ 2299,题目链接http://poj.org/problem?id=2299 题意: 给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列. 思路: 其实就是求逆序数,那么直接向到的就是冒泡了,交换一次,记录一次即可.但是n的范围达到50W,冒泡O(n^2)的复杂度铁定超时. 然后...发现曾经微软有一道笔试题类似就是求逆序数的,对,没错,用归并. 例:合并两个序列(1,3,5)(2,4,6),新序列第二个元素是2,那么它和它前面的3.5形成了逆序数对

POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 55048   Accepted: 20256 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

HDU 4911 Inversion(归并排序求逆序数)

归并排序求逆序数,然后ans-k与0取一个最大值就可以了. 也可以用树状数组做,比赛的时候可能姿势不对,树状数组wa了.. Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 578    Accepted Submission(s): 249 Problem Description bobo has a seque

POJ2299 Ultra-QuickSort(归并排序求逆序数)

归并排序求逆序数 Time Limit:7000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent

poj-2299 Ultra—QuickSort(归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 38688   Accepted: 13950 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

POJ 2299 Ultra-QuickSort (归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 47235   Accepted: 17258 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin