ArrayList上的MergeSort仅适用于ArrayList(Collection <! - ?extends E - > c)而不是ArrayList(int initialCapacity)?

时间:2017-05-21 22:55:54

标签: java algorithm arraylist mergesort

我正在处理interval上存在其ArrayList属性的排序startinterval的完整定义将在示例代码中显示为私有类。< / p>

我使用的实现是MergeSort,与我所指的Princeton's stuff非常相似,但问题是我发现此实现仅适用于创建辅助{{ 1}}使用ArrayList aux并使用ArrayList(Collection<? extends E> c)对其进行初始化,尝试使用原始列表中aux.set(i, intervals.get(i));项的相同顺序填充aux

我尝试使用interval创建aux并使用ArrayList(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 aux并使用ArrayList<Collection<? extends E> c>进行初始化?或者我的理解走错路? 感谢

1 个答案:

答案 0 :(得分:1)

感谢来自@maraca和@Dukeling的重要提示,经过一些工作,以下是我对此问题的看法:

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

A1 :这里有两个主要问题,我应该承认,在array MergeSort new ArrayList<Interval>(len) new Interval[len]实施的前期工作中,我没有陷入一些习惯性的想法,这里的影响是( 1)aux[i] = intervals[i]是否等于=? (2)aux.add(intervals.get(i))(仅用于解释,而不是在实际代码中使用new ArrayList<Interval>(len))等于ArrayList

对于问题(1),这里使用len = 4的实际情况仅定义[]大小的初始限制,但没有像空格持有者一样使用的实际项目填充到初始化列表中,例如如果我们设置[interval obj, interval obj, interval obj, interval obj],则初始化列表实际为new ArrayList<Interval>(len),而不是aux.set(i, intervals.get(i))。假设将java.lang.IndexOutOfBoundsException: Index: 0, Size: 0len一起使用,IDE将抛出interval,因为初始化和set方法无法在空列表中工作,因此没有真实对象填充到此列表中。此问题的解决方案是创建List<Interval> aux = new ArrayList<Interval>((Arrays.asList(new Interval(), new Interval(), new Interval(), new Interval())));个虚拟List<Interval> aux = new ArrayList<Interval>(intervals);个对象,以在初始化时填充列表,例如 aux.add(intervals.get(i)),但由于我们不关心在辅助列表上首先初始化的内容,只是用作占位符,如果对象太多,上面的代码可以替换为aux[i] = intervals[i]返回我们正确的解决方案。

对于问题(2),这里的实际案例是使用set()不等于add(),至少我们应该使用add()而不是aux,因为{{ 1}}会不断附加MergeSortMergeSort不会add(),因为aux需要完全相同大小的辅助收藏副本来帮助排序。仍然使用相同的示例来解释使用set()

时发生的情况

enter image description here

请注意,在第3次合并之后,add()大小会增加到原始列表的两倍大小,这会在复制回原始列表时导致索引问题。但是,如果我们使用clear(),则不会造成这种麻烦。

Q2 :如果仍想使用aux这是正确的方法吗?

A2 :正如@Dukeling所提到的,我们需要add() clear()在最终回合之前从原始列表到辅助列表,例如在第3次合并发生之前在上面的例子。

以下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}}的工作代码:

{{1}}