java - 无法解决Java Deque 迭代Bug
问题描述
在我进行测试时,我发现了我的代码中的错误。
我很难找到我的Deque
迭代器出了什么问题。它没有正确迭代,我不知道如何修复它。我已经包含了失败测试的屏幕截图和我完成的代码。
附注:我的教授希望迭代器在向前迭代或反向迭代时从头部出列元素,这就是为什么迭代器更难弄清楚的原因。
失败的单元测试截图: https ://imgur.com/a/srlmrNQ
非常感谢你的帮助!
完整的源代码:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Deque<E> implements Iterable<E>
{
private class DequeNode<E>
{
private DequeNode<E> _next;
private DequeNode<E> _previous;
private E _data;
private DequeNode(E data)
{
_data = data;
}
}
private DequeNode<E> _head;
private DequeNode<E> _tail;
private int _depth;
private static final int EXCLUSIVE_INDEX_START = -1;
public Deque()
{
_head = null;
_tail = null;
_depth = 0;
}
public boolean enqueue(E element) // This is INSERTION at the TAIL //TODO: DONE!!
{
DequeNode<E> newNode = new DequeNode<E>(element);
if (isEmpty())
{
_head = newNode;
}
else
{
_tail._next = newNode;
newNode._previous = _tail;
}
_tail = newNode;
_depth++;
return true;
}
public void enqueueAll(Iterable<E> elements)
{
for (E eachElement : elements)
{
enqueue(eachElement);
}
}
public boolean enqueueHead(E element) // This is insertion at the head //TODO: DONE!!
{
DequeNode<E> newNode = new DequeNode<E>(element);
if (isEmpty())
{
_tail = newNode;
}
else
{
_head._previous = newNode;
newNode._next = _head;
}
_head = newNode;
_depth++;
return true;
}
public E head()
{
checkForStackUnderflow();
return _head._data;
}
public E tail()
{
checkForStackUnderflow();
return _tail._data;
}
public E dequeue() // This is removal at the head //TODO: DONE!!
{
checkForStackUnderflow();
E removed = _head._data;
if (_head._next == null)
{
_tail = null;
}
else
{
_head._next._previous = null;
}
_head = _head._next;
_depth--;
return removed;
}
public E dequeueTail() // This is removal at the tail //TODO: DONE!!
{
checkForStackUnderflow();
E removed = _tail._data;
if (_head._next == null)
{
_head = null;
}
else
{
_tail._previous._next = null;
}
_tail = _tail._previous;
_depth--;
return removed;
}
public void clear()
{
_head = _tail = null;
_depth = 0;
}
public int depth()
{
return _depth;
}
public boolean isEmpty()
{
return _depth == 0;
}
public Iterator<E> iterator()
{
return new DequeIterator(this, false);
}
public Iterator<E> reverseIterator()
{
return new DequeIterator(this, true);
}
private void checkForStackUnderflow()
{
if (isEmpty())
{
throw new NoSuchElementException("Stack underflow captain!!!");
}
}
private class DequeIterator implements Iterator<E>
{
// The instance variables used throughout the program.
private int _index;
private Deque<E> _theList;
private DequeNode<E> _current;
private boolean _iterateReverse;
public DequeIterator(Deque<E> deque, boolean reverse)
{
_theList = deque;
_iterateReverse = reverse;
_index = 0;
_current = _head;
/* If the flag for reverse iteration is detected, then just start
the index at the end and iterate from the tail.
*/
if (reverse)
{
_index = _theList._depth - 1;
_current = _theList._tail;
}
}
public boolean hasNext()
{
boolean results;
// If we are reverse iterating check if the index is > than -1.
if (_iterateReverse)
{
results = _index > EXCLUSIVE_INDEX_START;
}
/* Getting here means that we are forward iterating so check if the
index is less than size AKA if we have more elements to go through.
*/
else
{
results = _index < _theList._depth;
}
return results;
}
public E next()
{
// If we don't have more elements to iterate through then we throw.
if (!hasNext())
{
throw new NoSuchElementException();
}
// Update the current to descent if we are reverse iterating.
if (_iterateReverse)
{
_current = _current._previous;
_index--;
}
// If we get to here then just update the current value forward.
else
{
_current = _current._next;
_index++;
}
return dequeue();
}
}
}
解决方案
由于代码在每次迭代中更新索引值并在迭代的每次出队操作中减小深度值,因此出现了深度小于索引值的用例,因此返回了不正确的 hasNext() 值(这似乎是所有失败的测试场景的根本原因)。
实现 hasNext() 的简单方法如下:
返回_theList._depth > 0;
这将适用于上述用例,因为在每个 next() 操作中都会执行 dequeue() 操作(这会降低深度值)。
推荐阅读
- ruby-on-rails - 为什么使用 Rails 保存副本数据时 `after_save` 不起作用?
- python - 如何将列表中的元素拆分为两个元素?
- c# - 如何在 C# 类中创建和启动 SignalR 集线器连接
- mysql - 使用内部选择的结果从单独的表中进行选择
- amazon-web-services - 电子邮件作为 DynamoDB 中客户订单的主键?
- python - 设想分解枚举的列表理解
- ssl - Certbot - 我如何选择 DNS 插件?
- docker - 容器内容未使用 docker volume 复制到 docker 主机
- excel - 循环遍历所有打开的工作簿时,代码在一个工作簿后退出循环
- php - 无法使用 shell_exec 在本地服务器上的 php 上执行 python 文件