有反转计数算法的问题

时间:2012-03-25 21:23:05

标签: java

我写了一个反转计数的实现。这是在线课程中执行的任务。但我得到的输入是不正确的,根据我所拥有的程序具有正确的语法。我不知道我错了 下面的程序是我的实现

import java.io.*;

class CountInversions {
    //Create an array of length 1 and keep expanding as data comes in

    private int elements[];
    private int checker = 0;

    public CountInversions() {
        elements = new int[1];
        checker = 0;
    }

    private boolean isFull() {
        return checker == elements.length;
    }

    public int[] getElements() {
        return elements;
    }

    public void push(int value) {
        if (isFull()) {
            int newElements[] = new int[elements.length * 2];
            System.arraycopy(elements, 0, newElements, 0, elements.length);
            elements = newElements;
        }
        elements[checker++] = value;
    }

    public void readInputElements() throws IOException {
        //Read input from file and until the very last input
        try {
            File f = new File("IntegerArray.txt");
            FileReader fReader = new FileReader(f);
            BufferedReader br = new BufferedReader(fReader);
            String stringln;
            while ((stringln = br.readLine()) != null) {
                push(Integer.parseInt(stringln));
            }
            System.out.println(elements.length);
            fReader.close();
        } catch (Exception e) {//Catch exception if any
            System.err.println("Error: " + e.getMessage());
        } finally {
//            in.close
        }
    }  
        //Perform the count inversion algorithm
    public int countInversion(int array[],int length){
        int x,y,z;
        int mid = array.length/2 ;
        int k;
        if (length == 1){
            return 0;
        }else{
            //count Leftinversion and count Rightinversion respectively
            int left[] = new int[mid];
            int right[] = new int[array.length - mid];

            for(k = 0; k < left.length;k++){
                left[k] = array[k];
            }

            for(k = 0 ;k < right.length;k++){
                right[k] = array[mid + k];
            }
            x = countInversion(left, left.length);
            y = countInversion(right, right.length);
            int result[] = new int[array.length];
            z = mergeAndCount(left,right,result);

            //count splitInversion
            return x + y + z;
        }   
    }

    private int mergeAndCount(int[] left, int[] right, int[] result) {
        int count = 0;
        int i = 0, j = 0, k = 0;
        int m = left.length, n = right.length;
        while(i < m && j < n){
            if(left[i] < right[j]){
                result[k++] = left[i++];
            }else{
                result[k++] = right[j++];
                count += left.length - i;
            }
        }
        if(i < m){
            for (int p = i ;p < m ;p++){
                result[k++] = left[p];
            }
        }
        if(j < n){
            for (int p = j ;p < n ;p++){
                result[k++] = right[p];
            }
        }
        return count;
    }
}
class MainApp{
    public static void main(String args[]){
        int count = 0;
        CountInversions cIn = new CountInversions();
        try {
            cIn.readInputElements();
            count = cIn.countInversion(cIn.getElements(),cIn.getElements().length);
            System.out.println("Number of Inversios: " + count);

        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }
}

2 个答案:

答案 0 :(得分:2)

如果数组长度为2的幂,则代码可以工作(实际上,我不确定是否这样,请参见下面的第二点)。

读取输入时,如果数组已满,则将数组大小加倍,但是从不将其大小调整为实际读取的项目数,这些项目存储在checker中。所以你的数组长度是2的幂,如果从文件读取的int的数量不是2的幂,你有一个太长的数组,其中一些尾随0元素对应于已分配但未从文件填充的地点。由于您使用数组的长度调用countInversions而不是读取项的数量,因此这些0也会被排序,从而产生一些虚假的反转。

读取输入后,分配一个新数组

int[] copy = new int[checker];
for(int i = 0; i < checker; ++i) {
    copy[i] = elements[i];
}
elements = copy;

复制元素,并丢弃容量错误的旧数组。

您的算法中的另一个问题是您永远不会更改原始数组,因为您为合并结果分配了一个新数组,

int result[] = new int[array.length];
z = mergeAndCount(left,right,result);

所以你要合并未排序的数组,这也可能会扭曲反转计数。由于您将输入数组的一半复制到新数组以进行递归调用,因此可以毫无问题地将合并结果放入传入的数组中,因此用

替换上面两行
z = mergeAndCount(left,right,array);

获取一个实际对数组进行排序并计算反转的方法。

答案 1 :(得分:1)

这篇文章正在解决使用Java进行计数反转的问题(除了文件阅读,你已经做好了) - Counting inversions in an array