分而治之算法(mergesort-algo)计算反演次数

tct7dpnv  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(418)

我试图解决计算倒数的问题,问题是:
序列?0,?1,…,?的反转??−1是一对索引0≤ ? < ? < ? 以至于??>??。从某种意义上说,序列的倒数可以衡量序列与排序的接近程度。例如,一个排序的序列(按非降序排列)根本不包含反转,而在按降序排列的序列中,任何两个元素构成一个反转(总共?(?− 1) /2反转)。 样本输入为:6 9 8 7 3 2 1 输出为:15
现在,我正在尝试合并排序算法,这个想法是每当我看到nextno。大于prevno。我会加上计数,最初是0。
这是合并算法:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class MergeSort {

static void Merge(int arr[],int l,int m, int r){

    int n1 = m-l+1;
    int n2 = r-m;

    int L[] = new int[n1];
    int R[] = new int[n2];

    for(int i=0;i<n1;i++)
        L[i] = arr[i+l];
    for(int i=0;i<n2;i++)
        R[i] = arr[m+1+i];

    int i=0,j=0;

    int k=l;

    while(i<n1&&j<n2){
        if(L[i]<R[j]){
            arr[k]=L[i];
            i++;
        }
        else{
            arr[k]=R[j];
            j++;
        }
        k++;
    }

    while(i<n1){
        arr[k] =L[i];
        i++;
        k++;
    }

    while(j<n2){
        arr[k] =R[j];
        j++;
        k++;
    }

   }

static void MergeSortBasic(int arr[],int l,int r) {

    if(l<r){
        int m = (l+r)/2;

        MergeSortBasic(arr,l,m);
        MergeSortBasic(arr,m+1,r);

        Merge(arr,l,m,r);
    }
   }

public static void main(String[] args) {
    QuickSortAlgo.FastScanner scanner = new QuickSortAlgo.FastScanner(System.in);
    int n = scanner.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) {
        a[i] = scanner.nextInt();
    }
  MergeSortBasic(a,0,n-1);
    for (int i = 0; i < n; i++) {
        System.out.print(a[i] + " ");
    }
}

static class FastScanner {
    BufferedReader br;
    StringTokenizer st;

    FastScanner(InputStream stream) {
        try {
            br = new BufferedReader(new InputStreamReader(stream));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    String next() {
        while (st == null || !st.hasMoreTokens()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }
}
   }

这一点我理解,但这里是解决这个问题,我遇到的,我不能理解。请有人帮我理解这个算法的解,特别是中点/平均部分。
解决方案:

import java.util.*;

public class Inversions {
private static long merge(int[] a, int[] b, int left, int ave, int right) {
    int i = left, j = ave, k = left;
    long inv_count = 0;
    while (i <= ave - 1 && j <= right) {
        if (a[i] <= a[j]) {
            b[k] = a[i];
            i++;
        } else {
            b[k] = a[j];
            inv_count += ave - i;
            j++;
        }
        k++;
    }
    while (i <= ave - 1) {
        b[k] = a[i];
        i++;
        k++;
    }
    while (j <= right) {
        b[k] = a[j];
        j++;
        k++;
    }
    for (i = left; i <= right; i++) {
        a[i] = b[i];
    }
    return inv_count;
}

private static long getNumberOfInversions(int[] a, int[] b, int left, int right) {
    long inv_count = 0;
    if (right <= left) {
        return inv_count;
    }
    int ave = left + (right - left) / 2;
    inv_count += getNumberOfInversions(a, b, left, ave);
    inv_count += getNumberOfInversions(a, b, ave + 1, right);
    inv_count += merge(a, b, left, ave + 1, right);
    return inv_count;
}

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int n = scanner.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) {
        a[i] = scanner.nextInt();
    }
    int[] b = new int[n];
    System.out.println(getNumberOfInversions(a, b, 0, a.length - 1));
}
}

我的问题是为什么我们有

inv_count += ave - i;

而不是简单地:

inv_count++;

比如这两个节目有什么不同??这个变量是怎么工作的?还有,你知道我以后怎样才能有效地学习到这一点吗?

qv7cva1a

qv7cva1a1#

为什么:inv\u count+=平均值-i;
正在合并的两个子数组已经从先前的递归中排序(或者子数组大小为1个元素的结束情况)。每次发现右子数组中的元素小于左子数组中的当前元素(a[j]<a[i])时,左子数组中剩余的元素数(ave-i)被添加到反转计数中,因为a[j]小于从a[i]到a[ave-1]的所有元素。

相关问题