在deque实现中调整圆形数组的大小

时间:2017-02-27 06:29:56

标签: java algorithm data-structures deque

我正在尝试使用循环数组实现Deque这里是我的代码(抱歉发布整个类)

public class Deque<Item> implements Iterable<Item> {

    private int frontIndex;
    private int backIndex;
    private static final int defaulSize = 8;
    private int size;
    private Item holder[];

    private int capacity;

    public Deque() {
        holder = (Item[]) new Object[defaulSize];
        this.size = 0;
        this.frontIndex = 0;
        this.backIndex = 0;
        this.capacity = defaulSize;
    }

    public boolean isEmpty() {

        return this.size == 0;

    }

    public int size() {
        return this.size;
    }

    public void addFirst(Item item) throws Exception {

        if (item == null) {

            throw new NoSuchElementException();
        }
        if (size == capacity) {

            doubleCapacity();
        }
        holder[this.frontIndex] = item;
        this.frontIndex = Math.floorMod((this.frontIndex + 1), capacity);
        size++;

    }

    public void addLast(Item item) throws Exception {

        if (item == null) {

            throw new NoSuchElementException();
        }

        if (size == capacity) {

            doubleCapacity();
        }
        holder[this.backIndex] = item;
        this.backIndex = Math.floorMod((this.backIndex - 1), capacity);
        size++;

    }

    public Item removeFirst() throws Exception {

        if (isEmpty()) {
            throw new Exception("Deque is empty.");
        }

        this.frontIndex = Math.floorMod((this.frontIndex - 1), capacity);
        this.size--;
        Item e = holder[this.frontIndex];
        holder[this.frontIndex] = null;
        return e;
    }

    public Item removeLast() throws Exception {

        if (isEmpty()) {
            throw new Exception("Deque is empty.");
        }
        this.backIndex = Math.floorMod((this.backIndex + 1), capacity);
        this.size--;

        Item e = holder[this.backIndex];
        holder[this.backIndex] = null;
        return e;
    }

    private void doubleCapacity() {

        int p = this.backIndex;
        int n = holder.length;
        int r = n - p; // number of elements to the right of p
        capacity = (n) * 2;
        Object[] a = new Object[capacity];
        System.arraycopy(holder, p, a, 0, r);
        System.arraycopy(holder, 0, a, r, p);
        holder = (Item[]) a;
        this.backIndex = n;
        this.frontIndex = 0;

    }

    private class DequeIterator<E> implements Iterator<E> {

        private int pos = 0;

        public boolean hasNext() {
            return holder.length > pos;
        }

        public E next() {

            return (E) holder[pos++];
        }

        public void remove() {
            throw new UnsupportedOperationException("Cannot remove an element of an array.");
        }
    }

    @Override
    public Iterator<Item> iterator() {
        return this.new DequeIterator<Item>();
    }

}

当我尝试使用deque调整圆形数组的大小时,问题就出现了,似乎所有索引都搞砸了

我使用的方法类似于在java实现中完成的实验

private void doubleCapacity() {

    int p = this.backIndex;
    int n = holder.length;
    int r = n - p; // number of elements to the right of p
    capacity = (n) * 2;
    Object[] a = new Object[capacity];
    System.arraycopy(holder, p, a, 0, r);
    System.arraycopy(holder, 0, a, r, p);
    holder = (Item[]) a;
    this.backIndex = n;
    this.frontIndex = 0;

}

如果将圆形数组用作deque,有没有特定的方法来调整圆形数组的大小,或者如何调整此deque的大小

(这不是家庭作业的个人研究)

1 个答案:

答案 0 :(得分:1)

问题基本上是由于事实

1-在向Deque

添加项目时,您没有正确更新frontIndex和backIndex

2-在容量加倍时不使用正确的索引。

问题1

当frontIndex和backIndex相等并且您在双端队列的任何入口点添加元素时,您需要更新它们,否则您将失去对Deque的控制权。示例:在开头,frontIndex和backIndex都是== 0。如果你添加一个项目让我们在前面说,之后你将有frontIndex = 1(正确)和backIndex = 0(不正确,因为位置0被新项目占用)。这有很多副作用

解决方案1 ​​

  public void addFirst(Item item) throws Exception {

      ... unchanged handling of capacity...

        holder[this.frontIndex] = item;
        //CHECK OF THE 2 INDEXES
        if(this.frontIndex==this.backIndex){
            this.backIndex= floorMod((this.backIndex - 1), capacity);
        }
        this.frontIndex = floorMod((this.frontIndex + 1), capacity);
        size++;
    }

     public void addLast(Item item) throws Exception {

      ... unchanged handling of capacity...

        holder[this.backIndex] = item;
        if(this.frontIndex==this.backIndex){
            this.frontIndex= floorMod((this.frontIndex + 1), capacity);
        }
        this.backIndex = floorMod((this.backIndex - 1), capacity);
        size++;
    }

注意,删除功能中也存在问题,您应该正确处理。我没有时间处理它,但解决方案很简单

问题2

你总是使用backIndex(它在概念上可以)来处理新数组中项目的副本,但理想情况下backIndex指向之前的位置 Deque中的第一个元素,所以使用该值混乱迪克本身就多了一点。 您还要为 new backIndex分配完全错误的索引(它应该等于新创建的数组的最后一个元素的索引而不是n,这是指 old的大小数组)和frontIndex(应该等于位置n,即最后一个填充项目后的一个元素)。

解决方案2

private void doubleCapacity() {

    int p = floorMod((this.backIndex+1 ), capacity);
    int n = holder.length;
    int r = n - p; // number of elements to the right of p
    capacity = (n) * 2;
    Object[] a = new Object[capacity];
    System.arraycopy(holder, p, a, 0, r);
    System.arraycopy(holder, 0, a, r, p);
    holder = (Item[]) a;
    //backIndex should be the last element of the whole array
    this.backIndex = capacity-1;
    //frontIndex must be 1 after the last element of the portio of array populated by items  
    this.frontIndex = n;
}

作为设计我将处理frontIndex和backIndex作为Deque中已经存在的第一个和最后一个元素的(循环)索引,而不是它们之前和之后的索引。但这只是我的方式。