C1-2018级算法第一次上机A题题解

冒泡排序(信助教的鬼话)

上机心路历程

  • 啊冒泡排序。。。那我就模拟,每次记录交换次数,最后输出结果就好了,冒泡排序,直接打板子。
  • 几分钟后。。。我去怎么还是TLE,我明明用了flag判断当没有发生交换时就退出循环,即使O(n2)也应该擦擦边过掉吧。
  • 百思不得其解。。。上机前似乎看到比赛简介中写:归并排序。对了!!!冒泡排序交换的过程,其实就是消除逆序对的过程呀,而且想想似乎是一对一的关系,有多少个逆序对,就需要交换多少次,所以这题便可以由冒泡排序的模拟问题,转化成归并排序求逆序对数的问题了,O(nlogn),perfect!

解题思路

如上所说,将冒泡排序的模拟问题,转化成归并排序求逆序对数的问题,而这个问题在之前多次做到,可以称之为“板子题”了,与归并排序唯一不同的地方是,多了一个语句用以记录逆序对数。

cnt += len1 - lPos;

即某步归并过程中消除的逆序对数等于当左数组指针(一个整型类型的下标)所指数大于右数组指针所指数时,左数组长度与左数组指针的差值。

#include <stdio.h>
#include <stdlib.h>
#define infinate 2147483647

int a[1000000];
long long cnt;

void Merge(int left,int mid,int right){
    int len1 = mid - left + 1;
    int len2 = right - mid;
    int i;
    int leftArray[len1 + 1],rightArray[len2 + 1];
    for(i = 0;i < len1;i++){
        leftArray[i] = a[left + i];
    }
    for(i = 0;i < len2;i++){
        rightArray[i] = a[mid + i + 1];
    }
    leftArray[len1] = rightArray[len2] = infinate;
    int lPos = 0,rPos = 0;
    for(i = left;i <= right;i++){
        if(leftArray[lPos] <= rightArray[rPos]){
            a[i] = leftArray[lPos++];
        }
        else{
            a[i] = rightArray[rPos++];
            cnt += len1 - lPos;//最关键的步骤,记录逆序数,因为左右各自有序,这次归并消除的逆序数可以用这个公式表示,除了这一步,其他所有都与归并排序算法一致
        }
    }
}

void mergeSort(int left,int right){
    if(left < right){
        int mid = (left + right) / 2;
        mergeSort(left,mid);
        mergeSort(mid + 1,right);
        Merge(left,mid,right);
    }
}
int main()
{
    long long n;
    scanf("%lld", &n);
    cnt = 0;
    int i;
    for(i = 0;i < n;i++){
        scanf("%d", &a[i]);
    }
    mergeSort(0,n - 1);
    printf("%lld",cnt);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值