2017-05-21 30 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