【问题标题】:Deque implementation with circular array issue具有循环数组问题的双端队列实现
【发布时间】:2018-07-12 11:55:25
【问题描述】:

我正在尝试完全实现 Deque,而不使用 java 库中已经创建的 Deque。我的代码可以编译,但输出并不像预期的那样。例如,容量应该作为参数提供给类,但结果显示实际容量最终比指定的量低 1。

我遇到的另一个问题是队列应该按照先进先出的方式工作。但这在结果中没有体现。有什么想法吗?

public class ArrayDeque<E> implements IDeque<E> {


    private int capacity;
    private E[] array;
    private int front;
    private int end;
    private int size;


    public ArrayDeque(int capacity) {

        this.array = (E[]) new Object[capacity];
        this.capacity = capacity - 1;
        front = 1;
        end = 0;
        size = 0;


    }


    private boolean isFull() {
        return (size == capacity);
    }


    private boolean isEmpty() {
        return (size == 0);
    }


    @Override
    public int size() {
        return size;
    }


    @Override
    public void addFirst(E elem) throws DequeFullException {
        if (isFull())
            throw new DequeFullException("samlingen er full!");
        array[front] = elem;
        front = (front + 1) % capacity; // use modulo to make sure the front restarts from initial position once it reaches capacity
        size++;
    }

    @Override
    public E pullFirst() throws DequeEmptyException {
        if (isEmpty())
            throw new DequeEmptyException("Samlingen er tom!");
        front = (front - 1) % capacity;
        size--;
        return array[front];
    }


    @Override
    public E peekFirst() throws DequeEmptyException {
        if (isEmpty())
            throw new DequeEmptyException("samlingen er tom!");

        System.out.println(array[(front - 1) % capacity]);
        return array[(front - 1) % capacity];
    }

    @Override
    public void addLast(E elem) throws DequeFullException {
        if (isFull())
            throw new DequeFullException("samlingen er full!");
        array[end] = elem;
        end = (end - 1) % capacity;
        size++;

    }

    @Override
    public E pullLast() throws DequeEmptyException {
        if (isEmpty())
            throw new DequeEmptyException("samlingen er tom!");
        end = (end + 1) % capacity;
        size--;
        return array[end];


    }


    @Override
    public E peekLast() throws DequeEmptyException {
        if (isEmpty())
            throw new DequeEmptyException("samlingen er tom!");
        System.out.println(array[(end + 1) % capacity]);
        return array[(end + 1) % capacity];
    }

}
public class Main {
    public static void main(String[] args){
    ArrayDeque<String> deque = new ArrayDeque<>(6);

    deque.addFirst("first");
    deque.addFirst("second");
    deque.addFirst("third");
    deque.addFirst("fourth");


    deque.peekFirst();
    deque.peekLast();
    deque.addLast("fourth");
    deque.addLast("last");
    deque.peekLast();
    deque.size();
    }
}

【问题讨论】:

  • 为什么你的双端队列从索引 1 开始?
  • "但结果显示实际容量最终比指定的数量低 1" - 可能是this.capacity = capacity - 1; 的原因?

标签: java arrays queue deque


【解决方案1】:

关于您遇到的容量问题: 您正在将阵列设置为具有用户传递的容量。例如,这意味着用户输入 6。现在在这里你将你的内部容量设置为容量 -1,这意味着它将是 5。现在,如果你使用较低的容量进行模运算,它会将位置设置为 0,即使它在技术上可以在 array[5] 中放置一些东西。这是您使用 Arrays.toString 运行的程序的打印,在每个 addFront() 之后打印您的数组:

[null, 0, null, null, null, null]
0
[null, 0, 1, null, null, null]
0
[null, 0, 1, 2, null, null]
0
[null, 0, 1, 2, 3, null]
0
[4, 0, 1, 2, 3, null]
0
[4, 5, 1, 2, 3, null]
5

这个问题的解决方案相当简单。将您的构造函数设置为如下所示:

public ArrayDeque(int capacity) {

    this.array = (E[]) new Object[capacity];
    this.capacity = capacity;
    front = 1;
    end = 0;
    size = 0;
}

此外,考虑到您的 FiFo 问题: 您可能需要考虑更好地跟踪您最后添加的元素以及应该返回的元素。这可能会引入两个新变量,但会使您的生活变得更加轻松。例如:

public void addFirst(E elem) throws DequeFullException {
    if (isFull())
        throw new DequeFullException("samlingen er full!");
    array[front] = elem;
    first = front;
    front = (front + 1) % (capacity); // use modulo to make sure the front restarts from initial position once it reaches capacity]
    size++;
    System.out.println(Arrays.toString(array));
}

假设first是一个整数,在构造函数中设置为0。您可以随意执行此操作,但这可以更好地跟踪您的第一个元素。

您的方法也有点问题,考虑到您在其中一些中向后遍历数组,而没有考虑ArrayOutOfBoundsException 在-1 的可能性。为了解决这个问题,您可能希望从以[0] 结尾和以[1] 开头的东西切换到以中间开头的东西。您必须找到一种方法在正确的位置放置和返回,也许检查您用于遍历的变量是否等于 0,以及它是否转到数组的另一侧。像这样:

public E pullFirst() throws DequeEmptyException {
    if (isEmpty())
        throw new DequeEmptyException("Samlingen er tom!");
    if(front == 0)
        front = capacity;
    front = (front-1) % (capacity);
    size--;
    return array[front];
}

这会在 main() 中使用此代码生成以下输出:

public class Main {
    public static void main(String[] args) {
        ArrayDeque<Integer> arrDq = new ArrayDeque<>(6);

        for(int i = 0; i < 6; i ++)
        {
            arrDq.addFirst(i);
        }
        for(int i = 0; i < 6; i ++)
        {
            System.out.println(arrDq.pullFirst());
        }
    }
}

输出:

[null, 0, null, null, null, null]
[null, 0, 1, null, null, null]
[null, 0, 1, 2, null, null]
[null, 0, 1, 2, 3, null]
[null, 0, 1, 2, 3, 4]
[5, 0, 1, 2, 3, 4]
5
4
3
2
1
0

对 Deque 的后部做同样的事情,它应该可以正常工作。我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 2012-01-30
    相关资源
    最近更新 更多