zoukankan      html  css  js  c++  java
  • <泛> 归并排序 及 逆序对

    今天写一个归并排序的模板,返回值为该序列的逆序对数

    基本思路

    归并排序就是利用二分的思想,将区间无限递归二分,直到当前划分区间只包含一个元素或没有元素的时候(我们认为这个序列是自动有序的),我们回溯到上一层,然后将当前层的左右两个区间合并为一个有序序列,然后继续回溯,回溯之后,当前层的左右两个区间都应该分别是已经经过合并的有序子区间,我们将这两个有序子区间再进行有序合并,再返回上一层,直到返回最大区间,则合并最大区间的左右有序子区间,得到有序序列。

    流程演示

    比如:22  3  1  5  4  7  9  1  8  0

    红色区间划分:22  3  1  5  4

    左边:22   3       右边   1   5   4

    左边:合并有序:3   22

    右边:5  4区间递归返回时候变为:4 5

    右边合并:1  4  5

    左右区间合并为一个区间:1  3  4  5  22

    至此左侧区间处理完毕

    右侧区间同理,得到有序序列:0  1  7  8  9

    最后合并整个区间

    0  1  1  3  4  5  7  8  9  22

    逆序对数

    我们利用归并的思想,它会将每个区间细分到最小,返回整合的时候,会进行左右区间合并,合并的时候就要比较左右区间当前值那个大,然后取小的那个,我们可以在比较的时候做记录,如果左侧的值小于右侧,我们就做记录,这样一路回溯,就会找到所有的逆序对数。

    我们利用归并排序的返回值来将此记录值输出到外部

    泛型代码:

    template<typename value_type, typename value_Ptr>
    int merge_sort(const value_Ptr& begin, const value_Ptr& end)
    {
        static std::vector<value_type> to(end - begin);
        static int cnt{ 0 };            //记录逆序对数
        if (end - begin <= 1)return 0;
    
        value_Ptr mid = begin + (end - begin) / 2;
    
        merge_sort<value_type>(begin, mid);
        merge_sort<value_type>(mid, end);
    
        //将上述两段区间顺序排列
        value_Ptr l = begin, r = mid;
        int k{ 0 }, index{ 0 };
    
        while (l < mid && r < end)
            if (*l < *r)to[k++] = *l++;
            else                      //如果左侧值小于右侧
            {
                cnt += mid - l;       //逆序对数记录
                to[k++] = *r++;
            }
    
        while (l < mid)to[k++] = *l++;
        while (r < end)to[k++] = *r++;
    
        for (index = 0; begin + index < end; ++index)*(begin + index) = to[index];
    
        return cnt;
    }

    测试与使用

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        ios::sync_with_stdio(false);
        int list[10]{ 22,3,1,5,4,7,9,1,8,0 };
        vector<int> v{ list,list + 10 };
    
        int cnt = merge_sort<int>(list + 0, list + 10);
        merge_sort<int>(v.begin(), v.end());
        for (auto it : v)cout << it << " ";
        cout << endl;
        for (auto it : list)cout << it << " ";
        cout << endl;
        cout << "逆序对数:" << cnt << endl << endl;
    
        char list_[10]{ 'r','c','2','A','z','b','8','0','r', '3' };
        vector<char>v_{ list_,list_ + 10 };
    
        cnt = merge_sort<char>(list_ + 0, list_ + 10);
        merge_sort<char>(v_.begin(), v_.end());
        for (auto it : v_)cout << it << " ";
        cout << endl;
        for (auto it : list_)cout << it << " ";
        cout << endl;
        cout << "逆序对数:" << cnt << endl << endl;
    }

    时间复杂度为:O(N * log N)

    感谢您的阅读,生活愉快~

  • 相关阅读:
    【转】Mongo初体验
    公益图书馆-学习笔记六 volist嵌套
    公益图书馆-学习笔记五-jquery来动态设置div高度
    公益图书馆-学习笔记四-复选框及jquery的onchange函数
    JQuery学习
    公益图书馆-学习笔记三
    公益图书馆-OnshelfController-代码学习
    公益图书馆-学习笔记二
    相似图像搜索从训练到服务全过程
    pickle 基础用法
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/9539504.html
Copyright © 2011-2022 走看看