这道题让我们实现一个环形数组类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)循环就会神奇的运行了。
- package freer.Cupenoruler.ASCII_Player;
- /**
- * 环形缓冲器。逻辑上首尾衔接.
- * @author Cupenoruler
- * @version 2.0
- */
- public class CircularBuffer<T>
- {
- /***************************************
- * 为保证buffer的put和 get有序进行,用两个索引
- * putIndex�待填入元素空位的索引
- * getIndex�待取出元素的索引
- ***************************************/
- private int putIndex = 0;
- private int getIndex = 0;
- private Object[] buffer = null;
- private int capability = 0; //buffer容量
- /**
- * jsut for test~
- * @param helloBaby
- */
- public static void main(String[] helloBaby){
- // CircularBuffer<String> a = new CircularBuffer<String>(1024);
- // System.out.println(a.putElement(null));
- // System.out.println(a.putElement("能存进去吗?"));
- // System.out.println(a.getElement());
- // System.out.println(a.getElement());
- // System.out.println(a.getElementWithBlock());
- // System.out.println("如果控制台木有这条信息,那么上一句代码造成阻塞了~");
- CircularBuffer<String> test = new CircularBuffer<String>(128);
- int i = 0;
- for(boolean canPut = true; canPut;){
- canPut = test.putElement("第" + (++i) + "个元素~~" );
- // System.out.println(canPut);
- }
- for(boolean canGet = true; canGet;) {
- String echoString = test.getElement();
- canGet = (null != echoString);
- if(canGet)
- System.out.println(echoString);
- }
- }
- /**
- *
- * @param capability 缓冲区大小
- */
- public CircularBuffer(int capability)
- {
- this.capability = capability;
- initialize();
- }
- /**
- * @param capability
- */
- private void initialize()
- {
- this.buffer = new Object[this.capability];
- }
- /**
- * 填入元素:注意此函数会造成阻塞
- * @param element- 带填入元素
- */
- public void putElementWithBlock(T element){
- while(!putElement(element)){
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- System.out.println("put�߳��ж�");
- }
- }
- }
- /**
- * 取出元素,注意此函数会造成阻塞
- */
- public T getElementWithBlock(){
- T temp = null;
- while(null == (temp = getElement()) ){
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- System.out.println("get�߳��ж�");
- }
- }
- return temp;
- }
- /**
- * 填入元素,此函数会立即返回
- * @param element
- * @return true-操作成功 false-操作失败(待填入数据的元素位还有数据)
- */
- public boolean putElement(T element)
- {
- if(element == null)
- throw new NullPointerException("非要往里边填null么?");
- /* 不要覆盖已有数据 */
- if(this.buffer[this.putIndex] != null){
- return false;
- }
- this.buffer[this.putIndex] = element;
- this.putIndex++;
- this.putIndex %= this.capability;
- return true;
- }
- /**
- * 取出元素,此函数会立即返回
- * @return null-待取数据的元素位为null ,非null-成功取出数据
- */
- @SuppressWarnings("unchecked")
- public T getElement()
- {
- if(this.buffer[this.getIndex] == null){
- return null;
- }
- //拿到引用,并将元素位置空
- Object temp = this.buffer[this.getIndex];
- this.buffer[this.getIndex] = null;
- this.getIndex++;
- this.getIndex %= this.capability;
- return (T)temp;
- }
- public void clear(){
- for(int i = 0, length = buffer.length; i < length; i++){
- buffer[i] = null;
- }
- this.putIndex = 0;
- this.getIndex = 0;
- }
- /****************************************************\
- * --Setter and Getter-- *
- \****************************************************/
- public int getCapability()
- {
- return capability;
- }
- // 新元素是以 索引0 向 索引length 的顺序 put入
- // 有鉴于此,这里倒过来枚举,防止出现“同向追赶”导致落空的的囧事;
- public boolean isEmputy(){
- for(int i = this.buffer.length-1; i > 0; i--){
- if( this.buffer[i] != null ){
- return false;
- }
- }
- return true;
- }
- }