算法入门之归并排序

前言:

        脱更5个月的小编回来啦!这段时间小编一直都在摆烂,相比上学期小编似乎丧失了学习的动力,从今天起小编将重拾信心与动力,持续更新,小编将会用一个月的时间更新算法入门系列。今天我要分享的是算法入门之排序与查找(归并排序)。

        归并排序的主要思想是分治算法与合并,首先介绍一下分治算法,将一个复杂的问题分为几个简单的小问题,解决局部问题最后合并答案解决复杂问题。分治法是归并排序的主要思路,首先将要排序的数组分为尽量相等长的两部分,紧接又继续往下分,一直分到一个数组里有一个元素即可(采用递归),因为每一个元素都自带有序性,然后就是合并了,合并的过程就是一种排序。合并也是归并排序的精髓所在。

        以下我将具体介绍思路:假设有一个长度为5的数组,里面元素有5,9,12,1,4;首先我们要获取两个边界,左边界和右边界确定分割线,然后递推下去。

以上便是归并排序。

代码如下:

//归并排序
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);     // [x,m)左半部分
        merge_sort(A, m, y, T);     // [m,y)右半部分
        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 j = x; j < i ; j++)
            A[j] = T[j];
    }
}

int main(){
    int n;
    cin >> n;
    vector<int> a(n);
    vector<int> t(n);
    for(int i = 0; i < n; ++i){
        cin >> a[i];
    }
    merge_sort(a.data(),0,n,t.data());
    for(int i = 0; i < n; ++i){
        cout << a[i] << " ";
    }
    return 0;
}

接下来我们要解决逆序列的个数问题,什么是逆序列呢?

问题描述:

        逆序对问题。给一列数a1 , a2 , … , an,求它的逆序对数,即有多少个有序对(i,j),使

i < j a i > a j
        我们不难发现,归并排序每一次排序就是一次逆序重组,我们只要加入一个计数器,而每一次重新排序的时候,还未加入到辅助数组里的元素m-p个都比辅助数组里的元素大,所以只要连加m-p就可以。
以下是代码:
        
//归并排序
int merge_sort(int* A, int x, int y, int* T){
    int cnt = 0;
    if(y - x > 1){
        int m = x + (y - x) / 2;
        int p = x , q = m , i = x;      // 用指针控制各个部分起始位置
        merge_sort(A, x,m , T);     // [x,m)左半部分
        merge_sort(A, m, y, T);     // [m,y)右半部分
        while(p < m || q < y){          // 如果左半部分或右半部分元素没有合并完成则继续
            if (q >= y || (p < m && A[p] < A[q]))   // 如果 q >= y,意味着右半部分的数组元素已经全部放入了辅助数组中,此时不管左半部分是否还有剩余元素,都会将左半部分的元素加入到辅助数组中。
                T[i++] = A[p++];    // 左右两部分数组都还有剩余元素,此时会比较左右两部分当前元素的大小,如果 A[p] < A[q],则将左半部分的元素加入到辅助数组中;
            else{
                T[i++] = A[q++];    // 否则将右半部分元素直接加入辅助数组中
                cnt += m - p;
            }
        }
        for(int j = x; j < i ; j++)
            A[j] = T[j];
    }
    return cnt;
}

int main(){
    int n;
    cin >> n;
    vector<int> a(n);
    vector<int> t(n);
    for(int i = 0; i < n; ++i){
        cin >> a[i];
    }
    cout << merge_sort(a.data(),0,n,t.data());
//    for(int i = 0; i < n; ++i){
//        cout << a[i] << " ";
//    }
    return 0;
}

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值