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);
    }
    
  • 相关阅读:
    LeetCode OJ 107. Binary Tree Level Order Traversal II
    LeetCode OJ 116. Populating Next Right Pointers in Each Node
    LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
    LeetCode OJ 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode OJ 98. Validate Binary Search Tree
    老程序员解Bug的通用套路
    转载 四年努力,梦归阿里,和大家聊聊成长感悟
    转载面试感悟----一名3年工作经验的程序员应该具备的技能
    Web Service和Servlet的区别
    关于spring xml文件中的xmlns,xsi:schemaLocation
  • 原文地址:https://www.cnblogs.com/dabric/p/14804225.html
Copyright © 2011-2022 走看看