迭代器堆栈 hasNext() 不返回 true

Iterator stack hasNext() not returning true

我正在尝试遍历对象数组。使用 next() 方法有效,所以我猜测我的迭代器 class 和构造函数正在工作。

由于某些原因,我在 hasNext() 方法运行时没有得到任何输出。

        Iterator it = hej.iterator();
    Object j = it.next();
    System.out.println(j);


    while(it.hasNext()){
        Object i = it.next();
        System.out.println(i + " ");
    }

"hej" 是我的对象数组。

我的 next() 代码;和 hasNext() 方法如下:

public class StackIterator implements Iterator<Object>{

// fields
private int element = 0;
private final Object[] elements;
private final int max;

// constructor

public StackIterator(Object[] values, int maxIndex) {
    elements = values;
    max = maxIndex;
}

// methods
public boolean hasNext() {
    return element < max;
}

public Object next() {
    return elements[element++];
}       

}

构造Object Array和Object Array的文件依赖一个接口:

public interface Stack {
int size();
boolean isEmpty();
void push(Object element);
Object pop();

Object peek();

Iterator<Object> iterator();

}

然后在另一个文件中解释这些方法:

public class StackExample implements Stack {

// fields
int length = 0;
Object[] arr;

// constructor
public StackExample() {arr = new Object[length];}


// method returns size of object array
public int size() {
    return arr.length;

}

// method checks if object is empty
public boolean isEmpty() {
    boolean result = false;
    if (arr.length == 0){
        result = true;

    }
    return result;
}

// method for push
public void push(Object element) {
    newBiggerObj();
    arr[0] = element;
}

// returns the first object of the stack
public Object pop() {
    Object[] temp = new Object[arr.length-1];
    Object first = arr[0];
    for (int i = 0; i<arr.length-1; i++){
        temp[i] = arr[i+1];
    }arr = temp;
    return first;
}

// returns the object on top of stack
public Object peek() {
if (isEmpty()){
    try{
        throw new Exception("Stack empty, can't peek!");
    }
    catch(Exception e){
        return e.getMessage();
    }
}

else {
    Object first = arr[0];
    return first;
}

}

// method for push method
private void newBiggerObj(){
    Object[] temp = new Object[arr.length+1];
    for (int i = 0; i<arr.length; i++){
        temp[i+1] = arr[i];
    }
    arr = temp;
}

public String toString(){
    String str = "";
    for (int i = 0; i < arr.length; i++){
        str = str + arr[i] + " , ";
    }return str;
}

public Iterator<Object> iterator() {
    return new StackIterator(arr, length);
}

}

令我困扰的是 Iterator 方法在其自身内返回 class Stack Iterator 的一个实例。我在上面发布的。所以我真正的问题似乎是我的字段没有被赋予任何价值,因为我自己并没有在构造函数中赋予任何值。

我测试所有这些的主要方法如下:

public class Teststack {
public static void main(String[] args){
    // new instane of class StackExample
    StackExample hej = new StackExample();

    // test for the different methods
    System.out.println(hej.isEmpty());
    System.out.println(hej.size());
    hej.push(4);
    hej.push("hej");
    hej.push(6);
    hej.push(5);
    System.out.println(hej.size());
    System.out.println(hej.peek());
    System.out.println(hej.pop());
    System.out.println(hej.toString());
    System.out.println(hej.isEmpty());


    System.out.println("Testing Iterator: ");
    // test for iterator
    Iterator it = hej.iterator();
    Object j = it.next();
    System.out.println(j);


    while(it.hasNext()){
        Object i = it.next();
        System.out.println(i + " ");
    }
}

}

几个问题:

  • 您在创建迭代器后调用 Object j = it.next();,然后检查 hasNext。您正在增加元素索引。因此,如果您只有一个元素,则不会进入 while 循环。此外,如果您的自定义数据结构为空,即数组没有元素,那么您很容易出现 ArrayIndexOutOfBoundException。
  • 您将始终迭代并打印 n-1 个元素而不是 n 个元素。
  • 迭代后,您的指针将始终指向最后一个元素并且永远不会重置。所以下次你将无法迭代你的元素。它是一次性迭代器。

尽量不要打电话 Object j = it.next() 语句,只是while循环。似乎你有一个只有 1 个元素的数组。

在您的 StackExample class 中,当元素被压入或弹出时,我没有看到 length 变量被更新。因此,length 将始终为 0,对 it.hasNext() 的调用将始终 return false。

您不需要将长度作为单独的参数传递。您可以在 StackIterator 构造函数中找到数组的长度并使用它。

另请注意,由于您在每次推送和弹出时都创建了一个新数组,因此由 StackExample#iterator() 编辑的迭代器 return 将在每次 push/pop 之后变得陈旧,因为它可以工作在堆栈的旧 copy/state 上。

问题在这里:

public Iterator<Object> iterator() {
    return new StackIterator(arr, length);
}

length 字段永远不会改变,所以它的值总是 0。您可以将代码更改为:

public Iterator<Object> iterator() {
    return new StackIterator(arr, arr.length);
}

此外,在从迭代器中检索元素之前,您应该始终调用 it.hasNext。你这样做的事实:

Iterator it = hej.iterator();
Object j = it.next();

工作只是运气。


除此之外,我可以感觉到您的堆栈实现设计很糟糕。这里有一些改进代码的提示:

  • 内部数组应使用不同于 0 的默认大小进行初始化。例如10(在 java.util.ArrayList 实施中完成)。
  • 您应该避免在从堆栈中添加 (push) 或删除 (pop) 元素时创建新数组。取而代之的是,您应该使用 length 字段来控制 stack.
  • 中的元素数量
  • 新尺寸的值应基于另一个公式而不是 array.length + 1。例如,尝试使用 int newSize = array.length / 2 * 3;.
  • 仅在必要时调整内部数组的大小。调用 push 时,仅当您恰好需要增加数组的大小时才执行此操作。调用 pop 时,如果数组的当前长度(即 array.length)远大于 class 的 length 字段的值,则执行此操作。
  • 永远不要忘记在 pushpop 方法上更新 length 的值。

此代码存在许多问题:

  • StackIterator 构造函数中,maxIndex 没有边界检查。调用者可以传入大于 values.length、小于 0 等的数字
  • next 方法中,没有直接或通过调用 hasNext() 检查结束条件。呼叫者可以继续呼叫 next() 并查看 max 之外的元素,甚至在他们应该获得 NoSuchElementException.
  • 时获得 ArrayIndexOutOfBoundsException
  • 当元素被压入或弹出时,Stack class 从不增加或减少其 length 字段。
  • Stack class 将 length 与数组分开跟踪,即使它总是在每次推送或弹出时调整数组的大小,但 Java 数组已经知道他们的大小。 (但请看下一项。)
  • Stack class 在每次推送或弹出时调整数组的大小,这是非常低效的。通常像这样的 classes 只在必要时调整数组的大小,允许 'slack' space,以提供摊销的常数时间性能(请参阅 ArrayList)。但是,如果您这样做,则有必要 null 弹出的项目以避免意外保留对象。
  • Stack 在数组的开头添加和删除元素。这是非常低效的,因为这意味着必须在 每次 推送或弹出时进行 O(n) 重新洗牌。
  • peek()方法考虑到了Stack可能为空的可能性,而pop()方法则没有。空 Stack 上的 pop() 将抛出 ArrayIndexOutOfBoundsException.
  • Stack 不是通用的 class。它持有 ObjectStack 的用户必须从 peek()pop() 转换为 return 值,而且它不是类型安全的。在您的示例中,您显示的堆栈是 StringInteger 的异质混合物。这是非常 Java 1.2 的处理方式,虽然不一定是错误的,但您应该考虑参数化 Stack.