归并排序及应用

void merge_sort(int *s,int l,int h,int *t)  //t辅助数组
{
    if(h-l>1){
        int mid = l+(h-l)/2;
        int i=l,p=l,q=mid;
        merge_sort(s,l,mid,t);
        merge_sort(s,mid,h,t);
        while(p<mid||q<h){
            if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++];
            else t[i++]=s[q++];
        }
    }
    for(int i=l;i<h;i++)    s[i]=t[i];
}

int main()
{
    int s[10]={10,3,5,2,1,4,8,6,9,7},t[10]={10,3,5,2,1,4,8,6,9,7};
    for(int i=0;i<10;i++)   printf(i==9?"%d\n":"%d ",s[i]);
    merge_sort(s,0,10,t);
    for(int i=0;i<10;i++)   printf(i==9?"%d\n":"%d ",s[i]);
    return 0;
}

逆序对问题,给出一个序列,求逆序对数,及有多少个又需对(i,j)是的i<j但ai>aj。n高达10e6

可以种归并排序求解,或者也可以用树状数组。

int c;
void merge_sort(int *s,int l,int h,int *t)  //t辅助数组
{
    if(h-l>1){
        int mid = l+(h-l)/2;
        int i=l,p=l,q=mid;
        merge_sort(s,l,mid,t);
        merge_sort(s,mid,h,t);
        while(p<mid||q<h){
            if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++];
            else t[i++]=s[q++],c+=mid-p;
        }
    }
    for(int i=l;i<h;i++)    s[i]=t[i];
}

int main()
{
    int s[10]={6,7,8,9,10,1,2,3,4,5},t[10]={6,7,8,9,10,1,2,3,4,5};
    for(int i=0;i<10;i++)   printf(i==9?"%d\n":"%d ",s[i]);
    merge_sort(s,0,10,t);
    for(int i=0;i<10;i++)   printf(i==9?"%d\n":"%d ",s[i]);
    printf("%d\n",c);
    return 0;
}

应用:

考分鄙视(exam)

时间限制: 1 Sec  内存限制: 64 MB
提交: 15  解决: 5
[提交][状态][讨论版]

题目描述

 
Whence这个学期考了n次试,每一次都有一个0~20000之间的整数分数。Whence本来的状态应该是每一次考试都比前一次多一分(除第一次),
但由于他很不稳定,偏差可能很大。对于第i次考试,如果有第j次考试满足l≤j<i≤n,且以第j次考试分数作为基准估计的第i次考试成绩比实际成
绩低,就说第i次考试鄙视了第j次考试(估计分可以超过20000)。为了提高自信,Whence想知道他这个学期所有考试总共有多少次鄙视。

输入

第1行n (l<n≤100000);
第2行为n次考试成绩。

输出

1行,这个学期所有考试的总共鄙视次数(总数可能很大,只需要输出总数mod 12345的值)。

样例输入

4
1 3 3 5

样例输出

3

提示

样例说明:第一次考试的分数是1,那么估计应该是第二次为2,第三次为3,第四次为4, 但第二次实际分数为3,比2大,这是1次鄙视;第四次实际分数为5,比估计的4大,这也是1次鄙视;第二次考试的分数是3,那么估计应该是第三次为4,第 四次为5,实际分数分别是3和5,所以没有鄙视;第三次考试的分数为3,那么估计第四次是4,但实际为5,这又是1次鄙视。因此总鄙视次数为3次。

分析:当i-j<s[i]-s[j]受到鄙视,即s[j]-j<s[i]-i受到鄙视。 把数组倒置。 即求逆序对。。

#include <cstring>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <queue>
#define fi first
#define se second
#define pi pair<int,int>
#define md make_pair
#define ha pair<int,pair<int,pi> >
using namespace std;
const int inf=0x3f3f3f3f;
int c,s[100010],t[100010];
void merge_sort(int *s,int l,int h,int *t)  //t辅助数组
{
    if(h-l>1){
        int mid = l+(h-l)/2;
        int i=l,p=l,q=mid;
        merge_sort(s,l,mid,t);
        merge_sort(s,mid,h,t);
        while(p<mid||q<h){
            if(q>=h||(p<mid&&s[p]<=s[q])) t[i++]=s[p++];
            else t[i++]=s[q++],c=(c+mid-p)%12345;
        }
    }
    for(int i=l;i<h;i++)    s[i]=t[i];
}

int main()
{
    //freopen("data.in","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",s+i),s[i]-=i,t[i]=s[i];
    reverse(s+1,s+n+1);
    reverse(t+1,t+n+1);
    //for(int i=1;i<=n;i++)printf("%d ",s[i]);printf("\n");
    merge_sort(s,1,n+1,t);
    //for(int i=1;i<=n;i++)printf("%d ",s[i]);printf("\n");
    printf("%d\n",c);
    return 0;
}
时间: 2024-10-07 01:05:05

归并排序及应用的相关文章

算法 排序NB二人组 堆排序 归并排序

参考博客:基于python的七种经典排序算法     常用排序算法总结(一) 序前传 - 树与二叉树 树是一种很常见的非线性的数据结构,称为树形结构,简称树.所谓数据结构就是一组数据的集合连同它们的储存关系和对它们的操作方法.树形结构就像自然界的一颗树的构造一样,有一个根和若干个树枝和树叶.根或主干是第一层的,从主干长出的分枝是第二层的,一层一层直到最后,末端的没有分支的结点叫做叶子,所以树形结构是一个层次结构.在<数据结构>中,则用人类的血统关系来命名,一个结点的分枝叫做该结点的"

codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)

题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 megabytes input standard input output standard output Mashmokh's boss, Bimokh, didn't like Mashmokh. So he fired him. Mashmokh decided to go to university

归并排序(Merge Sort)

更详细的请看这篇博文:http://www.cnblogs.com/jingmoxukong/p/4308823.html 我只做个人学习和补充 基于分治法的排序,比较简单.个人感觉其核心是数组左右拆分之后类似队列的比较.类似两两合并之类的算法都可以参考 分为3个步骤,拆开为树结构遍历->向上合并 特别做了一张gif来更好的理解归并排序 左边集合比较通过就左边索引前进,右边集合比较通过则右边索引前进 比较结果放入结果数组中 最后如果多出一个就把这一个直接加入结果数组 为了易于学习,代码直接使用了

两路归并排序

链表两路归并 #include<iostream> #include<assert.h> using namespace std; struct node { int val; node * next; node(int v) { val=v; next=NULL; } }; node * merge(node* list1 , node * list2) { assert(list1!=NULL&&list2!=NULL);//括号中是希望出现的正确的情况  no

算法基础:分治模式,归并排序ΘΘΘΘΘΘ知识小结

1.分治模式在每层递归时都有三个步骤:分解,解决,合并 2.归并排序算法完全遵循分治模式: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列 解决:使用归并排序递归的排序两个子序列 合并:合并两个已排序的子序列以产生已排序的答案 3.分析分治算法所需要的时间计算: 假设T(n)是规模为n的一个问题的运行时间,若问题足够小,如对某个常量c,n≦c,则直接求解需要常量时将,我们将其写作Θ(1).假设吧原问题分解成a个子问题,每个子问题的规模是原问题的1/b(对归并排序,a和b都为2,然

归并排序

基本思想: 1)首先需要一个临时空间temp用来存放合并后的元素,长度为排列好的元素总个数. 2)取两个指针,分别为左右部分数组的头元素. 3)比较指针指向元素,将较小(较大)的那个放入temp(注意相等时不做元素位置交换),并将两指针向后移动一个step. 4)循环步骤3直到其中一段数组没有剩余元素(其中一段被遍历完). 5)将还有元素剩余的另外一半数组元素直接放入temp尾部 代码实现: public static void merge(int[] list, int left, int m

基本排序算法(冒泡排序 选择排序 插入排序 快速排序 归并排序 基数排序 希尔排序)

冒泡排序 public static void bubbleSort(int[] arr){ int lgn = arr.length; for (int i = 0; i < lgn - 1; i++) { for (int j = 0; j < lgn - 1 - i; j++) { if(arr[j] > arr[j + 1]){ int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } } 选择排序 publ

利用Python实现归并排序

利用python进行归并排序,摘抄自http://blog.csdn.net/minxihou/article/details/51821052 "代码真的不是一气呵成的,而且也不是想当然写出来的.可能需要反复断点中断来查看是否有逻辑错误.在理解了问题的基础下我们需要先把大体的代码框架最好先写出来,特别是主要的逻辑判断语句.但是不需要太care我循环体或者判断里面语句怎么实现,当你把这一步做到的时候能避免很多不必要的错误发生." 1 import random 2 3 def Conf

面试必考三大排序算法C++代码(快速排序、归并排序、堆排序)

前两个为C++风格代码,后一个为C风格代码,除了输入输出,其它无差别,但C输入输出要比C++更快. 快速排序 1 #include <iostream> 2 using namespace std; 3 4 void swap(int num[], int i, int j) 5 { 6 int temp = num[i]; 7 num[i] = num[j]; 8 num[j] = temp; 9 } 10 11 int partition(int num[], int left, int

python实现归并排序,归并排序的详细分析。

学习归并排序的过程是十分痛苦的.它并不常用,看起来时间复杂度好像是几种排序中最低的,比快排的时间复杂度还要低,但是它的执行速度不是最快的.很多朋友不理解时间复杂度低为什么运行速度不一定快,这个不清楚的伙伴可以看下我之前发表的文章http://www.cnblogs.com/Lin-Yi/p/7301535.html看完之后也许你会对时间复杂度有一个新的认识. 我谈的观点往往不是官方的定义,我希望能帮助更多基础薄弱的同学读懂思想~ 归并排序: 先分开再合并,分开成单个元素,合并的时候按照正确顺序合