高效算法设计_再谈排序和检索(归并排序,逆序数对)

归并排序

上一个分治法的扩展

划分:把序列分成元素个数尽量相等的两半。
递归求解:把两半的元素分别排序
合并:把两个有序表合并成一个

输入:
8
1 2 12 11 9 7 13 20
输出:
1 2 7 9 11 12 13 20
#include <stdio.h>
#define MAXSIZE 1024
void merge_sort(int *A,int x,int y,int *T){
    //T是辅助空间
    int i;
    if(y-x>1){
        //递归入口,所剩元素大于1,只有一个元素没有必要排序
        int m=x+(y-x)/2;//分治第一步,划分,技巧,向中间靠拢
        int p=x,q=m,i=x;
        merge_sort(A,x,m,T);//分治第二步,递归求解。
        merge_sort(A,m,y,T);
        while(p<m||q<y){//只要有一个序列非空,就要继续合并
            if(q>=y||(p<m&&A[p]<=A[q]))
            //第二个序列为空,或者两个序列都不为空,比较小的赋值,赋值A[p].
                T[i++]=A[p++];
            else T[i++]=A[q++];
            //否则第二个不为空,且第一个为空,或者,两个都不为空,且A[p]<=A[q]时,才赋值A[q]
        }
        for(i=x;i<y;i++)   A[i]=T[i];
        //右边的y是取不到的
    }
}
void print(int* A,int n)//比赛中避免最后一个空格检查出错误。
{
    for(int i = 0 ; i < n; i++)
    {
        if(i)
        {
            printf(" %d",A[i]);
        }
        else
        {
            printf("%d",A[i]);
        }
    }
    printf("\n");
}

void process()//输入程序。
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int A[MAXSIZE];
        int T[MAXSIZE];
        for(int i = 0 ; i < n ; i++)
        {
            scanf("%d",&A[i]);
        }
        merge_sort(A,0,n,T);
        print(A,n);
    }
}
int main(int argc,char* argv[])
{
    process();
    return 0;
}

逆序对数

题目: 给一列数a1,a2,a3,…,an。求它的逆序对数,即有多少个有序对(i,j),使得i
输入:
8 
1 9 6 3 4 7 9 0 
输出:
0 1 2 3 3 4 6 6 10 12 13 13 
0 1 3 4 6 7 9 9
13
第一行为计数过程表示cout逐渐自加的过程.

计算步骤:
刚开始归并排序两两分组 (1,9)(6,3)||(4,7)(9,0)
后面一位和前面一位进行对比,如果 i<j 且 ai>aj,逆序数对就加1
对于前半部分 count=0+1; 重排合并后(1,9,3,6) count=0+1+1+1.
对于后半部分count=3+0+1;重排合并后(4,7,0,9)count=3+0+1+2+0;
然后再重排合并(1,3,6,9,0,4,7,9)count=6+4+2+1+0=13,及最终结果

#include <stdio.h>
#define MAXSIZE 1024

int count,k=0;
int K[MAXSIZE];
void mergeSort(int* A,int x,int y,int* T)
{
    if(y-x>1)
    {
        int m = x + (y - x) / 2 ;
        int p=x,q=m,i=x;
        mergeSort(A,x,m,T);
        mergeSort(A,m,y,T);
        while(p < m || q < y)
        {
            //if(m >= high || (l < mid && iArr[l] < iArr[m]))
            if(q>= y||(p < m && A[p] <= A[q]))//=与号不能漏
            {
                T[i++] = A[p++];
            }
            else
            {
                T[i++]=A[q++];
                count+=m-p;
                printf("%d ",count);
            }
        }
        for(int j = x ; j < y ; j++)
        {
            A[j]=T[j];
        }
    }
}

void print(int* A,int n)
{
    for(int i = 0 ; i < n; i++)
    {
        if(i)
        {
            printf(" %d",A[i]);
        }
        else
        {
            printf("%d",A[i]);
        }
    }
    printf("\n");
}

void process()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        count = 0;
        int A[MAXSIZE];
        int T[MAXSIZE];
        for(int i=0;i<n;i++)
        {
            scanf("%d",&A[i]);
        }
        mergeSort(A,0,n,T);
        print(A,n);
        printf("%d\n",count);
    }
}

int main()
{
    process();
    getchar();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值