zoukankan      html  css  js  c++  java
  • 递归O(NlgN)求解逆序数

    导言

    第一次了解到逆序数是在高等代数课程上。当时想计算一个数列的逆序数直觉就是用两重循环O(n^2)暴力求解。现在渐渐对归并算法有了一定的认识,因此决定自己用C++代码小试牛刀。

    逆序数简介

    由自然数12…,n组成的不重复的每一种有确定次序的排列,称为一个n级排列(简称为排列);或者一般的,n个互不同元素排成一列称为“一个n级排列”。例如,12344312都是4级排列,而24315是一个5级排列。

    在一个n级排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个“逆序”。

    例子:
      123成为自然排列 逆序数为 0
      324一列数 逆序排列有(32) (31) (21) (41) 所以逆序数是4

     

    代码实现

     

    #include <cstdio>
    #include <cstring>
    
     
    
    const int N = 4;   //测试数组的大小
    
    int cnt;  //全局变量
    
     
    
    void mergeSort(int *a,int p,int q,int *T){
    
        if(p+1>=q) return;
    
        int m=p+(q-p)/2;
    
        mergeSort(a,p,m,T);
    
        mergeSort(a,m,q,T);
    
        //merge
    
        for(int x=p,y=m,i=p;i<q;i++){
    
            if(x<m&&y<q&&a[x]<a[y] || y>=q) T[i]=a[x++];   //往‘左边’加
    
            else{
    
                
    
                T[i] = a[y++];
    
                cnt += (m-x);   //此处为重点,每向加入右边部分一个数时,逆序数应增加左边尚未被加入T的元素个数
    
            }
    
        }
    
        for(int i=p;i<q;i++)
    
            a[i] = T[i];
    
    }
    
    int main(){
    
        int T[N];   //辅助数组,即额外空间代价O(N)
    
        int a[]={3,2,4,1};
    
        cnt = 0;  //初始cnt为0
    
        mergeSort(a,0,N,T);
    
        printf("逆序数为:%d
    ",cnt);
    
        return 0;
    
    }

    结语

    对比先前两重循环暴力求解逆序数的做法,可以证明归并求解的时间复杂度是O(NlgN)。因此,当N较大时,可以发现本归并算法的明显高效很多。

  • 相关阅读:
    CSS定位(Position)
    深入理解Javascript闭包(二)
    深入理解Javascript闭包(一)
    如何将页脚固定在页面底部
    JQuery中$.fn的用法示例
    关于HttpWebRequest.KeepAlive
    Fiddler 教程
    js数组的操作
    oracle 修改字段类型的方法(转)
    Oracle查看表结构的几种方法(转后加工)
  • 原文地址:https://www.cnblogs.com/SeaSky0606/p/4567805.html
Copyright © 2011-2022 走看看