简体   繁体   English

ArrayList上的MergeSort仅与ArrayList(Collection <? extends E> c)不是ArrayList(int initialCapacity)吗?

[英]MergeSort on ArrayList only work with ArrayList(Collection<? extends E> c) not ArrayList(int initialCapacity)?

I am working on sort interval which exist on an ArrayList with its start property, the full definition of interval will show in sample code as private class. 我排序工作interval ,其存在于一个ArrayList ,其start性能,充分定义interval将显示在示例代码为私有类。

The implementation I am using is MergeSort , and very similar to Princeton's stuff which I refer to, but problem is I find this implementation only work with creating auxiliary ArrayList aux with ArrayList(Collection<? extends E> c) and initialize it with aux.set(i, intervals.get(i)); 我正在使用的实现是MergeSort ,与我引用的普林斯顿大学的东西非常相似,但是问题是我发现此实现仅适用于使用ArrayList(Collection<? extends E> c)创建辅助ArrayList aux并使用aux.set(i, intervals.get(i));对其进行初始化aux.set(i, intervals.get(i)); which try to fill aux with same order of interval items from original list 尝试用原始列表中interval项的相同顺序填充aux

I try to work it out with creating aux with ArrayList(int initialCapacity) and initialize it with aux.add(intervals.get(i)) , but failed. 我尝试通过使用ArrayList(int initialCapacity)创建aux并使用aux.add(intervals.get(i))对其进行初始化来解决aux.add(intervals.get(i)) ,但是失败了。 And I still could not figure out why this way doesn't work ? 而且我仍然不知道为什么这种方式行不通?

The full code which can directly used for debug: 可以直接用于调试的完整代码:

public class Test {
    private class Interval {
        // Will use start property to sort
        int start;
        int end;
        Interval() { 
            start = 0; 
            end = 0; 
        }
        Interval(int s, int e) { 
            start = s; 
            end = e; 
        }
        @Override
        public String toString() {
            return "[" + start + "," + end + "]";
        }
    }

    public void sortHelper(List<Interval> intervals) {
        int len = intervals.size();
        // Only this way works
        List<Interval> aux = new ArrayList<Interval>(intervals);
        // This way NOT work ?
        //List<Interval> aux = new ArrayList<Interval>(len);
        sort(intervals, aux, 0, len - 1);
    }

    public void sort(List<Interval> intervals, List<Interval> aux, int lo, int hi) {
        if(hi <= lo) {
            return;
        }
        int mid = lo + (hi - lo) / 2;
        sort(intervals, aux, lo, mid);
        sort(intervals, aux, mid + 1, hi);
        mergeHelper(intervals, aux, lo, mid, hi);
    }

    public void mergeHelper(List<Interval> intervals, List<Interval> aux, int lo, int mid, int hi) {
        // Only this way works
        for(int i = lo; i <= hi; i++) {
            aux.set(i, intervals.get(i));
        }
        // Combine with List<Interval> aux = new ArrayList<Interval>(len);
        // this way NOT work ?
        //for(int i = lo; i <= hi; i++) {
        //    aux.add(intervals.get(i));
        //}
        int left = lo;
        int right = mid + 1;
        for(int k = lo; k <= hi; k++) {
            if(left > mid) {
                intervals.set(k, aux.get(right++));
            } else if(right > hi) {
                intervals.set(k, aux.get(left++));
            } else if(less(aux.get(right), aux.get(left))) {
                intervals.set(k, aux.get(right++));
            } else {
                intervals.set(k, aux.get(left++));
            }
        }
    }

    public boolean less(Interval a, Interval b) {
        return a.start - b.start < 0;
    }

    public static void main(String[] args) {
        Test m = new Test();
        Interval one = m.new Interval(1, 3);
        Interval two = m.new Interval(2, 6);
        Interval three = m.new Interval(8, 10);
        Interval four = m.new Interval(15, 18);
        List<Interval> intervals = new ArrayList<Interval>();
        // Adding order as [2,6],[1,3],[8,10],[15,18]
        intervals.add(two);
        intervals.add(one);
        intervals.add(three);
        intervals.add(four);
        m.sortHelper(intervals);
        // Expected sort result should be
        // [1,3],[2,6],[8,10],[15,18]
        for(Interval i : intervals) {
            System.out.println(i);
        }
    }    
}

Could anyone help me on understanding why must create auxiliary ArrayList aux with ArrayList<Collection<? extends E> c> 谁能帮助我理解为什么必须使用ArrayList<Collection<? extends E> c>创建辅助ArrayList aux ArrayList<Collection<? extends E> c> ArrayList<Collection<? extends E> c> and initialize it with aux.set(i, intervals.get(i)); ArrayList<Collection<? extends E> c>并使用aux.set(i, intervals.get(i));对其进行初始化aux.set(i, intervals.get(i)); ? Or my understanding goes the wrong way ? 还是我的理解走错了路? Thanks 谢谢

Thanks for important hint from @maraca and @Dukeling, after some work, below is my opinion for the issue here: 感谢@maraca和@Dukeling的重要提示,经过一些工作,以下是我对此问题的看法:

Q1 : Why using List<Interval> aux = new ArrayList<Interval>(len); Q1 :为什么使用List<Interval> aux = new ArrayList<Interval>(len); with aux.add(intervals.get(i)); aux.add(intervals.get(i)); not work ? 不行 ?

A1 : There are two main issues here, I should admit I fail into some habitual thoughts as previous work with array implementation of MergeSort , the impact here are (1) new ArrayList<Interval>(len) equal to new Interval[len] or not ? 解答1 :这里有两个主要问题,我应该承认我以前习惯使用MergeSort array实现工作时有些习惯性想法,对这里的影响是(1) new ArrayList<Interval>(len)等于new Interval[len]或不是吗 (2) aux[i] = intervals[i] (just for explain, not use = in real code) equal to aux.add(intervals.get(i)) ? (2)等于aux.add(intervals.get(i)) aux[i] = intervals[i] (仅用于解释,不使用=在实际代码中aux.add(intervals.get(i))

For problem (1), the real case here is using new ArrayList<Interval>(len) will only define the initial limitation of ArrayList size, but no real items used like space holder to fill into the initialized list, eg If we set len = 4 , the initialized list is actually [] , not [interval obj, interval obj, interval obj, interval obj] . 对于问题(1),这里的实际情况是使用new ArrayList<Interval>(len)仅定义ArrayList大小的初始限制,但没有像空格符之类的实际项用于填充初始化列表,例如,如果设置len = 4 ,初始化的列表实际上是[] ,而不是[interval obj, interval obj, interval obj, interval obj] Assume using new ArrayList<Interval>(len) with aux.set(i, intervals.get(i)) , IDE will throw out java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 , that's because no real object fill into this list as initialized and set method cannot work on an empty list. 假设使用带有aux.set(i, intervals.get(i)) new ArrayList<Interval>(len) ,IDE将抛出java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 ,这是因为没有真正的对象填充此列表已初始化,并且set方法无法在空列表上使用。 The solution for this issue is create len numbers of dummy interval objects to fill in list when initialized, such as List<Interval> aux = new ArrayList<Interval>((Arrays.asList(new Interval(), new Interval(), new Interval(), new Interval()))); 针对此问题的解决方案是创建len虚设数interval对象初始化时,比如,以填补在列表中List<Interval> aux = new ArrayList<Interval>((Arrays.asList(new Interval(), new Interval(), new Interval(), new Interval()))); , but since we don't care what initialized first on auxiliary list, just used as place holder and in case of the objects are too many, above code can be replaced with List<Interval> aux = new ArrayList<Interval>(intervals); ,但是由于我们不在乎首先在辅助列表上初始化的对象,仅用作占位符,并且在对象过多的情况下,可以将以上代码替换为List<Interval> aux = new ArrayList<Interval>(intervals); which return to our right solution. 回到我们正确的解决方案。

For problem (2), the real case here is using aux.add(intervals.get(i)) not equal to aux[i] = intervals[i] , at least we should use set() instead of add() , because add() will continually append on aux , which not MergeSort suppose to, because MergeSort require exactly same size auxiliary collection copy to help sorting. 对于问题(2),这里的实际情况是使用aux.add(intervals.get(i))不等于aux[i] = intervals[i] ,至少我们应该使用set()而不是add() ,因为add()将连续追加到aux ,而这并不是MergeSort假定的,因为MergeSort需要大小完全相同的辅助集合副本来帮助排序。 Still use same example to explain what happened when using add() 仍然使用相同的示例来解释使用add()时发生的情况

在此处输入图片说明

Note after the 3rd merge, the aux size increase to double size of original list, this will cause indices issue when copy back to original list. 请注意,在第三次合并后, aux大小将增加到原始列表的两倍,这将导致在复制回原始列表时出现索引问题。 But if we are using set() will not cause this trouble. 但是,如果我们使用set()不会造成此麻烦。

Q2 : If still want to use add() what is the proper way ? Q2 :如果仍然想使用add()的正确方法是什么?

A2 : As mentioned by @Dukeling, we need to clear() the aux before final round copy from original list to auxiliary list, eg like before the 3rd merge happen on above example. A2 :如@Dukeling所述,我们需要在从原始列表到辅助列表的最终回合复制之前clear() aux ,例如,如上例中的第三次合并之前。

The working code with add() and clear() below: 下面带有add()clear()的工作代码:

public void mergeHelper(List<Interval> intervals, List<Interval> aux, int lo, int mid, int hi) {
    aux.clear();
    for(int i = 0; i < lo; i++) {
        aux.add(null);
    }
    for(int i = lo; i <= hi; i++) {
        aux.add(intervals.get(i));
    }
    int left = lo;
    int right = mid + 1;
    for(int k = lo; k <= hi; k++) {
        if(left > mid) {
            intervals.set(k, aux.get(right++));
        } else if(right > hi) {
            intervals.set(k, aux.get(left++));
        } else if(less(aux.get(right), aux.get(left))) {
            intervals.set(k, aux.get(right++));
        } else {
            intervals.set(k, aux.get(left++));
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM