zoukankan      html  css  js  c++  java
  • 归并排序

    1 归并排序算法

    归并排序的核心思想:分治

    1. 确定分界点:mid = (l + r) / 2
    2. 递归排序左部分和右部分
    3. 归并,合二为一

    归并的方法:外排

    1. 辅助数组help[N]i指向左部分的左边界,j指向右部分的左边界;
    2. 比较q[i]q[j]的大小,小的放入help数组里;
    3. 如果左部分的没有copy将剩下的copy到help数组内,对右部分做同样的操作
    4. 最后将help数组中存储的数组copy到原数组内
    #include <iostream>
    using namespace std;
    
    const int N = 100010;
    
    int n, q[N], tmp[N];
    
    void merge_sort(int q[], int l, int r)
    {
        if (l >= r) return;
        
        int mid = l + r >> 1;
        merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
        
        int i = l, j = mid + 1, k = 0;
        
        while (i <= mid && j <= r)
        {
            if (q[i] <= q[j]) tmp[k++] = q[i++];
            else tmp[k++] = q[j++];
        }
        
        while (i <= mid) tmp[k++] = q[i++];
        while (j <= r) tmp[k++] = q[j++];
        
        for (i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) scanf("%d", &q[i]);
        
        quick_sort(q, 0, n - 1);
        
        for (int i = 0; i < n; i++) printf("%d", q[i]);
    }
    

    2 归并排序应用

    逆序对数

    给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

    逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

    数的范围

    1≤n≤100000

    解决方法

    使用归并排序的思想:

    假设现在的merge_sort函数可以返回数组中所有的逆序对的个数

    归并排序:

    1、找数组的中间点mid,将数组分为[l, mid]和[mid + 1, r];

    2、递归排序左部分,递归排序右部分

    3、合并左右区间

    逆序对产生的情况:

    1、两个数同时出现在左半边:merge_sort(L, mid)

    2、两个数同时出现在右半边:merge_sort(mid + 1, R)

    3、一个数在左一个数在右

    对于第三种情况,整体的思路:右半边的第一个数,看左半边部分中有多少个比其大,以此类推遍历整个右半边的数

    归并排序中的归并过程中,有两个指针i, j分别指向左右部分,谁小会将谁添加到辅助数组内,当q[i] > q[j]时,此时[i, mid]之间的数都大于q[j],这时就会产生mid -i + 1个逆序对也就是说,在归并的过程中,当要输出q[j]时,此时给最终的逆序对的结果就加上mid - i + 1即可。

    逆序对最多的数量:整个数组为逆序是的逆序对最多,最多为n(n-1)/2个。

    #include <iostream>
    
    using namespace std;
    
    const int N = 100010;
    
    typedef long long LL;
    
    int n;
    int q[N], tmp[N];
    
    LL merge_sort(int l, int r)
    {
        if (l >= r) return 0;
        
        int mid = l + r >> 1;
        LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);
        
        int k = 0, i = l, j = mid + 1;
        while (i <= mid && j <= r)
        {
            if (q[i] <= q[j]) tmp[k++] = q[i++];
            else 
            {
                tmp[k++] = q[j++];
                res += mid - i + 1;
            }
        }
        
        while (i <= mid) tmp[k++] = q[i++];
        while (j <= r) tmp[k++] = q[i++];
        
        for (int i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
        
        return res;
    }
    
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; i++) cin >> q[i];
        
        cout << merge_sort(0, n - 1);
    }
    
  • 相关阅读:
    写了一个自动打包并发布到tomcat的脚本
    查看并更改mysql编码
    MyBatis无法根据中文条件查询出结果
    服务器端PHP多进程编程
    PHP-popen()&nbsp;函数打开进程文件指针
    php并发处理
    PHP能得到你是从什么页面过来的,r…
    PHP如何解决网站大流量与高并发的…
    基于PHP的cURL快速入门
    Mysql内存表的用处
  • 原文地址:https://www.cnblogs.com/dabric/p/14804225.html
Copyright © 2011-2022 走看看