[CareerCup] 14.6 CircularArray 環形陣列

Grandyang發表於2015-11-24

 

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)迴圈就會神奇的執行了。

 

相關文章