poj1007 稳定排序 归并排序

/**
 * poj1007 稳定排序 归并排序
 * 正好在这里重新复习一下归并排序
 * 归并排序的思想是,把一个序列二分拆成前半段和后半段,递归深入的方法,使得前后的两个半段序列都是有序的(mergesort函数)
 * 然后将两个序列合并成一个有序的序列(merge函数)
 * 合并时,先给前后两个序列都做一个副本,然后向原来两个序列的空间内依次填充两个子序列中更小的一个
 * 如果填充的值来自右边的子序列,那么就有逆序数产生,逆序数统计时自增(左子序列剩余的元素个数)
 * 为什么这么自增一画就知道啦
 */
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
const int MAX_LEN = 51;
const int MAX_NUM = 101;
char dna[MAX_NUM][MAX_LEN];
char tmp[MAX_LEN];
struct point{
    int idx;
    int rcount;
} p[MAX_NUM];

int cmp(const void* a, const void* b){
    point *p1 = (point*)a, *p2 = (point*)b;
    //逆序数升序
    if(p1->rcount != p2->rcount){
        return p1->rcount - p2->rcount;
    }
    //idx升序
    else{
        return p1->idx - p2->idx;
    }
}

//将data[l]....data[q] 和data[q+1]...data[r]两个有序序列合并成一个有序序列
void merge(char data[],int l,int q,int r,int& count){
    const int len1 = q-l+1,len2 = r-q;
    char a1[len1],a2[len2];
    for(int i=0;i<len1;++i){
        a1[i] = data[l+i];
    }
    for(int i=0;i<len2;++i){
        a2[i] = data[q+1+i];
    }

    int k = l,idx1=0,idx2=0;
    while(idx1<len1 && idx2<len2){
        if(a1[idx1] <= a2[idx2]){
            data[k++] = a1[idx1++];
        }
        else{
            data[k++] = a2[idx2++];
            count += (len1 - idx1);//计算逆序数 逆序一定是两个序列之间才有逆序,一个序列内部都是有序的,因此只要计算数从右边序列进入大序列时,左边序列还剩几个,那就是本次移动的逆序数
        }
    }
    //如果剩下的都是左边的,逆序数就都已经统计完了,不用再加了
    while(idx1<len1){
        data[k++] = a1[idx1++];
    }
    //如果剩下的都是右边的,好像也不用统计了,因为idx1 = len1了
    while(idx2<len2){
        data[k++] = a2[idx2++];
        count += (len1 - idx1);
    }
    
}

void mergesort(char data[],int l,int r,int& count){
    if(l<r){
        int q = (l+r)/2;
        //先令左右两个子序列有序
        mergesort(data,l,q,count);
        mergesort(data,q+1,r,count);
        //再将两个有序的子序列合并成一个序列
        merge(data,l,q,r,count);
    }
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i){
        scanf("%s",dna[i]);
        memcpy(tmp,dna[i],n);

        p[i].idx = i;

        mergesort(tmp,0,n-1,p[i].rcount);
    }

    qsort(p,m,sizeof(point),cmp);

    for(int i=0;i<m;++i){
        printf("%s\n",dna[p[i].idx]);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值