2017-05-21 31 views
0

我在interval上工作,它存在于ArrayList及其start属性中,interval的完整定义将在示例代码中显示为私有类。归并上的ArrayList只的ArrayList(收藏<? extends E> c)不的ArrayList(INT参数:initialCapacity)工作?

我使用的实现是MergeSort,并且非常相似,Princeton's stuff我参考一下,但问题是我觉得这个实现只有合作创建辅助ArrayList auxArrayList(Collection<? extends E> c)aux.set(i, intervals.get(i));初始化它试图填补auxinterval来自原始列表的项目

我尝试着创建auxArrayList(int initialCapacity)并用aux.add(intervals.get(i))初始化它,但是失败。我仍然无法弄清楚,为什么这样不行?

完整的代码,可以直接用于调试:

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); 
     } 
    }  
} 

谁能帮助我理解为什么必须建立辅助ArrayList auxArrayList<Collection<? extends E> c>aux.set(i, intervals.get(i));初始化呢?或者我的理解错误? 感谢

+0

@maraca,谢谢,但你能仔细检查一遍,其实我没有使用与原始类型ArrayList中,该ArrayList 只是一个构造函数我用于初始化长度有限的ArrayList,实际项目是'Interval'类型,声明为私有类 – Lampard

+0

是的,我在代码中看到并删除了注释。但是你的两条线并不相同,一条是制作一个副本,另一条是创建一个具有一定容量的空数组。 – maraca

+0

@maraca,没错,我知道这两个构造函数的区别,但问题是为什么需要这样的原始列表副本?只是初始化一个新的空列表,然后从原始列表中添加相同的订单项将无法与MergeSort一起使用,甚至更多,如果您只是使用'new ArrayList (间隔)'来复制一个列表而不是**'aux.set (i,intervals.get(i));'也行不通,这些东西让我困惑,如果你有时间可以在IDE上运行的行为,谢谢 – Lampard

回答

1

感谢来自@maraca和@Dukeling重要的暗示,经过一番工作,下面是我这里的问题意见:

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

A1:主要有两个问题在这里,我必须承认我失败到一些习惯性的想法,因为以前的工作与array实施MergeSort,这里的影响是:(1)new ArrayList<Interval>(len)等于new Interval[len]与否? (2)aux[i] = intervals[i](只是为了说明,而不是用在真正的代码=)等于aux.add(intervals.get(i))

对于问题(1),真正的情况在这里被使用。如果我们设置len = 4new ArrayList<Interval>(len)只能定义用于像空间持有人,以填补到初始化列表,如ArrayList大小的初始限制,但没有真正的项目,初始化名单其实是[],不[interval obj, interval obj, interval obj, interval obj]。假设使用new ArrayList<Interval>(len)aux.set(i, intervals.get(i)),IDE将丢弃java.lang.IndexOutOfBoundsException: Index: 0, Size: 0,这是因为没有真正的对象填充到此列表中,因为初始化并且set方法不能在空列表上工作。对于这个问题的解决方法是在初始化时创建len数字虚拟interval对象填写清单,如 List<Interval> aux = new ArrayList<Interval>((Arrays.asList(new Interval(), new Interval(), new Interval(), new Interval())));,但由于我们不关心什么初始化第一辅助名单上,只是用作占位符和对象的情况下,是太多了,上面的代码可以用List<Interval> aux = new ArrayList<Interval>(intervals);这回我们正确的解决方案所取代。

对于问题(2),这里真正的情况是使用aux.add(intervals.get(i))不等于aux[i] = intervals[i],至少我们应该用set()代替add(),因为add()将继续在aux,这不是MergeSort想追加,因为MergeSort需要准确相同大小的辅助收集副本以帮助排序。仍然使用同样的例子来解释发生了什么当使用3合并后add()

enter image description here

注意,aux尺寸增大到原来的列表的两倍大小,这将导致指数的问题,当拷贝回原来的名单。但如果我们使用set()不会造成这种麻烦。

Q2:如果仍然想使用add()什么是正确的方法是什么?

A2:由于@Dukeling提到的,我们需要从最初的名单最后一轮副本辅助列表,e.g像第三合并之前发生在上面的例子之前clear()aux

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++)); 
     } 
    } 
} 
+1

非常接近,除了A1(2):a [i] = b [i]与a.set(i,b.get(i))相同。添加总是添加一个附加元素a.add(i,b.get(i))将在位置i处插入元素,并将它们移到后面(如果索引被省略,元素将添加到最后一个位置之后)。 – maraca

+1

如果你正在用arr [counter ++] = something等计数器填充一个数组,那么这或多或少与list.add(某些东西)相对应。 – maraca