14.6 Implement a CircularArray class that supports an array-like data structure which can be efficiently rotated.The class should use a generic type, and should support iteration via the standard for (Obj o : CircularArray) notation.
這道題讓我們實現一個環形陣列類CircularArray,由於環形陣列需要呼叫rotate(int shiftRight)函式,在這裡,我們並不會真的去旋轉陣列,因為這樣十分不高效。我們採用另一種實現方法,用一個變數head來記錄環形陣列的起始位置,那麼呼叫rotate實際上就是改變head的位置而已。請參見如下程式碼:
public static class CircularArray<T> implements Iterable<T> { private T[] items; private int head = 0; public CircularArray(int size) { items = (T[]) new Object[size]; } private int convert(int idx) { if (idx < 0) { idx += items.length; } return (head + idx) % items.length; } public void rotate(int shiftRight) { head = convert(shiftRight); } public T get(int i) { if (i < 0 || i >= items.length) { throw new java.lang.IndexOutOfBoundsException("..."); } return items[convert(i)]; } public void set(int i, T item) { items[convert(i)] = item; } public Iterator<T> iterator() { return new CircularArrayIterator<T> (this); } private class CircularArrayIterator<TI> implements Iterator<TI> { private int _current = -1; private TI[] _items; public CircularArrayIterator(CircularArray<TI> array) { _items = array.items; } @Override public boolean hasNext() { return _current < items.length - 1; } @Override public TI next() { ++_current; TI item = (TI) _items[convert(_current)]; return item; } @Override public void remove() { throw new UnsupportedOperationException("..."); } } }
上述程式碼中主要有兩部分:
1. 實現CircularArray類
實現的過程中容易犯一些錯誤,比如:
- 我們不能新建一個泛類的陣列,我們必須cast陣列或者定義型別為List<T>.
- 取餘操作符%對於負數運算後會得到負數,這和數學家們定義的取餘運算不同,所以我們需要給負數序列加上items.length,時期變為正數再做運算。
- 我們必須一致地保證將原序列轉為旋轉序列。
2. 實現迭代器Iterator介面
為了使用迭代來遍歷陣列for (Obj o : CircularArray),我們必須實現迭代器Iterator介面:
- 修改CircularArray<T>的定義,新增implements Iteratble<T>。這需要我們新增一個iterator()方法給CircularArray<T>。
- 建立CircularArrayIterator<T>類implements Iterator<T>,這需要我們實現CircularArrayIterator的一些方法,如hasNext(), next(), 和 remove()。
一旦我們實現了上面兩項,for (Obj o : CircularArray)迴圈就會神奇的執行了。