【问题标题】:Using an iterator to print a set implemented by a separate chaining hash table使用迭代器打印由单独的链式哈希表实现的集合
【发布时间】:2022-01-01 08:09:04
【问题描述】:

我正在使用带有哈希表的单独链接在 Java 中创建一个集合的实现。目前,我只是尝试向表中添加 100 个随机整数,然后在我自己的 toString 实现中使用自建迭代器来打印表内容。我已通过调试器确认我的 100 个整数已添加到表中,但我对我的代码在打印时出错的地方感到困惑。

我从 toString 得到的当前输出只是花括号内的一个 int,如下所示:{59, }。

我已经逐步调试了几次,但无法确定问题出在我的迭代器、toString 或两者的组合上。这是下面的课程:

import java.util.*;
import java.io.*;

public class MySet {
// implements a set using a separate chaining hash table
    private class Node {
        private Integer element;
        private Node next;
        private Node(Integer e, Node n) {
            element = e;
            next = n;
        }
    }

private Node table[]; //an array of linked list
private int lastHash; //last hash value used
private int tableSize; //current number of lists in the table
private int numElements; //number of elements in the set

private final int primes[] = {7, 23, 59, 131, 271, 563, 1171,
        2083, 4441, 8839, 16319, 32467,
        65701, 131413, 263983, 528991};

private int primeIndex; //last prime used

private int nextPrime(int p) {
    //finds the next prime from the list above
    //used for resizing and the initial size
    while (primes[primeIndex] <= p)
        primeIndex++;
    return primes[primeIndex];
}

public MySet(int s) {
    //s is a hint for the initial size
    primeIndex = 0;
    tableSize = nextPrime(s);
    //table is an array of nodes
    table = new Node[tableSize];
    numElements = 0;
}

private void resize() {
    //"double" the table size and reinsert the values stored in the
    //current table. the table size should remain prime
    int oldTableSize = tableSize;
    Node oldTable[] = table;
    tableSize = nextPrime(oldTableSize);
    table = new Node[tableSize];
    for (int i = 0; i < oldTableSize; i++) {
        Node temp = oldTable[i];
        while (temp != null) {
            int h = hash(temp.element);
            Node tempNext = temp.next;
            Node temp1 = table[h];
            table[h] = temp;
            table[h].next = temp1;
            temp = tempNext;
        }
    }
}

private int hash(Integer k) {
    //return the hash function value for k
    return Math.abs(k.hashCode() % tableSize);
}

public boolean find(Integer e) {
    //returns true when e is in the set, otherwise returns false
    lastHash = hash(e); //remember the last hash value used
    //this can be useful in methods that call find
    Node temp = table[lastHash];
    while (temp != null) {
        if (temp.element.equals(e)) return true;
        temp = temp.next;
    }
    return false;
}

public void addElement(Integer e) {
    //if e is not in the set add e to the set otherwise the set does not change
    if(find(e)) {
        return;
    }
    //add e to the set
    int index = hash(e);
    if(table[index] == null) {
        table[index] = new Node(e, null);
    } else if(table[index].next == null) {
        table[index].next = new Node(e, null);
    } else {
        Node temp = table[index];
        while(temp.next != null) {
            temp = temp.next;
        }
        Node newNode = new Node(e, null);
        temp.next = newNode;
    }
    //if after adding the new element numElements > 2*tableSize then call resize
    numElements++;
    if(numElements > 2 * tableSize) {
        resize();
    }
    return;
}

//iterates through the entire table
public class MySetIterator implements Iterator<Integer> {
    private Node curNode;
    int index;
    //implements an iterator for the set
    public MySetIterator() {
        curNode = table[0];
        index = 0;
    }
    public boolean hasNext() {
        return curNode.next != null;
    }
    public Integer next() {
        if(!hasNext()) {
            if(index > tableSize) {
                System.out.println("\n End of table!");
            }
            index++;
            curNode = table[index];
        }
        curNode = curNode.next;
        return curNode.element;

    }
    public void remove() {
        //not implemented
    }
}

public Iterator<Integer> iterator() {
    //returns an iterator for the set
    return new MySetIterator();
}

public String toString() {
    //returns a string representation for the set
    //the string representation of the set is { followed by a comma delimiter list of set
    //elements followed by a }. The string for the empty set is { }
    StringBuilder string = new StringBuilder();
    if(numElements == 0) {
        return "{ }";
    }
    string.append("{ ");
    MySetIterator iterator = new MySetIterator();
    while(iterator.hasNext()) {
        string.append(iterator.next() + ", ");
    }
    string.append(" }");
    String toReturn = string.toString();
    return toReturn;
}

public static void main(String args[]) throws IOException {
    //Test driver
    MySet set = new MySet(0);
    Random rand = new Random();
    for(int i = 0; i < 100; i++) {
        set.addElement(rand.nextInt(100));
    }
    System.out.println(set);
}

}

如果有人能指出我在这里做错了什么可能会导致我的问题,我将不胜感激。我有一种感觉,我没有正确使用我的迭代器实现,但这并不一定意味着我的迭代器也是正确的。谢谢。

【问题讨论】:

    标签: java iterator set hashtable tostring


    【解决方案1】:

    迭代器的情况是它的用法如下:

    while (iterator.hasNext()) {
      doSomething(iterator.next());
    }
    

    就目前而言,hasNext() 返回 false 之前 next() 有机会寻找它。

    您的hasNext() 方法将需要完成查找下一个条目(如果有的话)的所有工作。

    【讨论】:

      【解决方案2】:

      您不应该在next() 中做任何事情,而是返回一个值并可能指向下一个潜在值。 hasNext() 应该简单地返回 true of false 如果它指向一个值。如果它返回false 并且有人调用next(),那是他们的问题,而不是你的问题。并且无需在您的 next() 方法中调用 hasNext。同样,这取决于用户。 hasNext() 应该只检查适当的变量以确保下一个值可用。目前,您的 curNode.next 立即返回 null。

      似乎在您调用new Node() 的任何地方,第二个参数都是空的。请记住,多个 ints 可以散列到同一个存储桶。所以桶需要包含所有这些ints。一种方法是使用链接列表,但据我所知,您似乎没有这样做。

      【讨论】:

        猜你喜欢
        • 2021-12-25
        • 1970-01-01
        • 1970-01-01
        • 2018-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-10
        • 2012-04-30
        相关资源
        最近更新 更多