zoukankan      html  css  js  c++  java
  • 怎样求逆序对数(Inverse Number)?

     #返回上一级

    @Author: 张海拔

    @Update: 2014-01-14

    @Link: http://www.cnblogs.com/zhanghaiba/p/3520089.html

      1 /*
      2  *Author: ZhangHaiba
      3  *Date: 2014-1-15
      4  *File: inverse_number.c
      5  *
      6  *this demo shows two method solving inverse number problem
      7  */
      8 
      9 #include <stdio.h>
     10 #define N 512
     11 #define INF 0x7fffffff; //value of sentinel
     12 int array[N];
     13 int left_tmp[N/2+10];
     14 int right_tmp[N/2+10];
     15 
     16 //public
     17 int inverse_number_cnt(int *, int);
     18 int inverse_number_cnt2(int *, int);
     19 void merge_sort(int *, int, int, int *);
     20 void set_array(int *, int);
     21 void show_array(int *, int);
     22 
     23 
     24 int main(void)
     25 {
     26     int n;
     27 
     28     scanf("%d", &n);
     29     set_array(array, n);
     30     int ans;
     31     ans = inverse_number_cnt(array, n);
     32     printf("%d
    ", ans);
     33     ans = inverse_number_cnt2(array, n);
     34     printf("%d
    ", ans);
     35     return 0;
     36 }
     37 
     38 int inverse_number_cnt(int *a, int n)
     39 {
     40     int i, j, cnt = 0;
     41 
     42     for (i = 0; i < n-1; ++i)
     43         for (j = i+1; j < n; ++j)
     44             if (a[i] > a[j])
     45                 ++cnt;
     46     return cnt;
     47 }
     48 
     49 
     50 //modify merge_sort:
     51 //add variable cnt
     52 //add code "*cnt = left_len - i;"
     53 void merge_sort(int *a, int l, int r, int *cnt)
     54 {
     55     if (l >= r) return;
     56     else {
     57         int m = l + (r-l)/2;
     58         merge_sort(a, l, m, cnt);
     59         merge_sort(a, m+1, r, cnt);
     60         int left_len = m-l+1, right_len = r-m, i, j = l;
     61         for (i = 0; i < left_len; ++i, ++j)
     62             left_tmp[i] = a[j];
     63         left_tmp[i] = INF;
     64         for (i = 0; i < right_len; ++i, ++j)
     65             right_tmp[i] = a[j];
     66         right_tmp[i] = INF;
     67         for (i = j = 0; l <= r; ++l) {
     68             if (left_tmp[i] <= right_tmp[j])
     69                 a[l] = left_tmp[i++];
     70             else {
     71                 a[l] = right_tmp[j++];
     72                 *cnt += left_len - i;
     73             }
     74         }
     75     }
     76 }
     77 
     78 
     79 int inverse_number_cnt2(int *a, int n)
     80 {
     81     int l = 0, r = n-1, cnt = 0;
     82 
     83     merge_sort(a, l, r, &cnt);
     84     return cnt;
     85 }
     86 
     87 
     88 void set_array(int *a, int n)
     89 {
     90     int i;
     91 
     92     for (i = 0; i < n; ++i)
     93         scanf("%d", a+i);
     94 }
     95 
     96 
     97 void show_array(int *a, int n)
     98 {
     99     int i;
    100 
    101     for (i = 0; i < n; ++i)
    102         printf(i == n-1 ? "%d
    " : "%d ", a[i]);
    103 }

    逆序对的定义:序列A中,当位置i < j,而对应值a[i] > a[j],则称(i, j)构成序列A的一个逆序对。

    解法一中,按照定义,通过两个for循环即可求出逆序对数。

    即以第i个的元素为起点,j从i+1开始到n-1结束按定义进行验证,从而统计逆序对的个数,显然i的范围是[0, n-2]。

    显然解法一的时间复杂度是O(n^2)。

    解法二的所用函数几乎就是调用了一个纯粹的归并排序,目的通过计数器cnt的地址来修改cnt,做完归并排序后返回。

    这个解法求逆序对数的原理是:对于某一次的归并(有序表的合并),类似二叉树的后序遍历,归并时当右子数组某个元素k进入根数组时,此时左子数组中,下标为i的元素以及它后面的所有元素都与k构成逆序对(左子数组的下标均<左子数组任何一个元素的下标,而k能进入根数组则说明它的值比左子数组剩下的所有元素都小,因此k的下标与上述元素的下标,均构成逆序对),所以有逆序对数要增加left_len - i,即:*cnt += left_len - i。

      #返回上一级

  • 相关阅读:
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS博客作业01--线性表
    C博客作业05--指针
    C语言博客作业04--数组
    C博客作业03--函数
    博客作业——循环结构
    C博客作业05-指针
    C博客作业04--数组
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3520089.html
Copyright © 2011-2022 走看看