从0开始学算法--排序(1.5归并排序)

算法理解:

  一个数组长度为n,他的前m个元素是升序的,后n-m个元素升序的,怎么使整个数组变成一个升序数组?

如n=6,m=3

1 3 5 2 4 6
1 2 3 4 5 6

排序前

排序后

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>

using namespace std;

const int maxn=1e5+1;
int A[maxn];
int T[maxn];//辅助数组。

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d",&A[i]);
    }
    int p=0,q=m,i=0;
    while(p<m||q<n){
        if(q>=n||(p<m&&A[p]<=A[q]))T[i++]=A[p++];
        else T[i++]=A[q++];
    }
    for(int i=0;i<n;i++){
        A[i]=T[i];
    }
    for(int i=0;i<n;i++){
        printf("%d ",A[i]);
    }
    printf("\n");
    return 0;
}

归并排序采用了分治的想法,一个数组如果左边有序,右边有序则进行合并,如果左边无序递归处理,同理右边也递归处理。

由于归并排序每次使严格二分,所以时间复杂度是O(nlogn)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>

using namespace std;

const int maxn=1e5+1;
int n;
int A[maxn];
int T[maxn];//辅助数组。

void merge_sort(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;
        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]))T[i++]=A[p++];
            else T[i++]=A[q++];
        }
        for(int i=x;i<y;i++){
            A[i]=T[i];
        }
    }
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&A[i]);
    }
    merge_sort(A,0,n,T);
    for(int i=0;i<n;i++){
        printf("%d ",A[i]);
    }printf("\n");
    return 0;
}

例一:求逆序对对数

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>

using namespace std;

const int maxn=1e5+1;
int n;
int A[maxn];
int T[maxn];//辅助数组。
int cnt;
void merge_sort(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;
        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]))T[i++]=A[p++];
            else T[i++]=A[q++],cnt+=m-p;
        }
        for(int i=x;i<y;i++){
            A[i]=T[i];
        }
    }
}

int main(){
    scanf("%d",&n);
    cnt=0;
    for(int i=0;i<n;i++){
        scanf("%d",&A[i]);
    }
    merge_sort(A,0,n,T);
    printf("%d\n",cnt);
    return 0;
}

原文地址:https://www.cnblogs.com/wz-archer/p/11685741.html

时间: 2024-10-04 03:17:53

从0开始学算法--排序(1.5归并排序)的相关文章

从0开始学算法--排序(1.12c++利用标准库排序)

1,简单数组按升序排序 sort(a,a+n); #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <cmath> #include <queue> using namespace std; const int maxn=1e5+10; int a[maxn]; i

从0开始学算法--排序(1.8桶排序)

算法理解: 桶排序是对计数排序的一种优化,在计数排序中x应该放在计数数组下表为x的位置上,这样如果重复数字较少,计数数组每个位置的利用率就非常小. 桶排序是将一系列大小近似的数字放在一个位置(每个桶维护一条有序的链表),这样提高每个位置的利用率,以提高效率. 以A[]={1,21,23,41,49}为例 假设每个桶里有10中元素,那么桶排序的结构如下图所示. #include <algorithm> #include <iostream> #include <cstring&

从0开始学算法--排序(1.7快速排序)

算法理解: 对于无序数组里的任意一个数字V,总有一部分数字小于V,一部分数字大于V.如果我们将比V小的数字放在V的前面,比V大的数字放在后面,那V所在的位置就是整个数组排序后V应该在的位置. 同时我们得到了两个连续的无序数组,和归并排序一样左右递归处理即可. #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio>

0基础学算法 第二弹 排序

大家好啊,这是0算法基础学算法系列第二篇,上次我在第一弹里讲了关于流程图的内容,我寻思着,这次讲些什么好呢,于是我决定,教大家一个很基础的算法,那就是排序,排序有很多方法,如果你有更多方法请在评论区里留言哦. 排序在程序中特别实用,常用的有快速排序,桶排序,冒泡排序,插入排序等等,在这里我不建议使用冒泡排序或者插入排序,建议桶排序和快速排序,这两个排序非常实用,时间复杂度低,理解起来也很容易,首先,你先思考一下,怎么用程序进行排序,然后你再来看看你的思路合理不合理,最后试着用程序实现它,实现后你

从0开始学算法--数据结构(2.3队列)

顾名思义:队列就像排序一样,先排队的人先得到处理 队列与栈类似:队列是一个先进先出表 首先考虑数组模拟,如果线性数组模拟,会导致占用空间过多,为什么?数组模拟栈会遇到这样的问题吗? 因为队列是一个先进先出表,比如加入5个元素占用的是数组下表的0-4号位置,这时候删除两个元素,0-1号位置.为了维护这个队列的结构就会导致0-1号位置占用但不利用. 栈取出的是数组尾部的元素,所以不会占用额外的空间. 优化:“将数组变为环形”(模的意义). 如果我们每次加入元素是给数组下表取模,那么整个数组就变成了环

从0开始学算法--基础数据结构(2.8并查集)

算法理解: 根据名字就能很好的理解这个算法,集合的合并和查询 合并什么?查询什么? 合并操作为:把x所在的集合和y所在的集合合并为一个集合.查询x和y是否在一个集合里. 如:元素为1-n,这n个元素分别在编号为1-n的集合中.如果将3和5合并成为一个集合,只需要将元素3指向元素5即可 现在把元素5和元素2所在的集合合并合并,5指向2 可以看到如果要查询2和3是不是在一个集合中,只需要查询2和3的祖先是不是同一个元素就可以了 查询祖先代码 //f[x]初始化为f[i]=i; int find_se

从0开始学算法--数据结构(2.4双端队列与单调队列)

双端队列是特殊的队列,它与队列不同的是可以将元素加入头或尾,可以从头或尾取出元素(滑稽-这部就是栈和队列结合了吗). c++标准库 头文件 #include<deque> 定义 deque<int>deq; 取出队头,尾元素 deq.pop_front(); deq.pop_back(); 访问队头,尾元素 deq.front(); deq.back(); 向队头,尾加入元素 deq.push_front(x); deq.push_back(x); 单调队列是在队列的基础上使它保持

0基础学算法 第五弹 填坑

这个填坑系列,是为了能够解决大家在前面的疑点,如果你在前面有哪些疑点,可以加入QQ群1031467671,群名称叫球君博客的填坑群,入群问题答案是 球君,我要是在博客里有什么不足的,或着有什么讲的不清楚的地方,可以进去发表建议,好今天这期我就来填坑了,昨天有人说第四弹的乘法思路没讲清楚,所以今天我重新讲讲. 乘法的思路简单的说就是还是依靠竖式的原理,有第二个数的第一位乘上上面的全部数,再让第二个数的第二位乘上上面所有的数,这个操作用一个嵌套循环就可以完成了,再是进位问题,这个进位和加法有些不同,

1150: 零起点学算法57——程序设计竞赛

1150: 零起点学算法57--程序设计竞赛 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 1303  Accepted: 742[Submit][Status][Web Board] Description 每年5月份,省里都要举行程序设计竞赛. 为了让最优秀的学生去参加比赛,我们一般需要做一个选拔工作. 现在你来帮老师完成这个任务哦. Input 多组测试数据,每组数据一行,该行先输入一个整数