繁体   English   中英

通过Hashtable迭代的无限循环

[英]Infinite Loop Iterating Through Hashtable

我正在尝试使用Hashtables在数组中找到最流行的单词。 由于某种原因,while循环无限循环。 我已经调试了,元素永远不会从它得到的第一个变化。 有关为什么会发生这种情况的任何想法?

这是我的代码:

import java.util.Hashtable;

public class MyClass {
  public String mostPopularString (String []words) {
    if (words == null)
            return null;
    if (words.length == 0)
            return null;
    Hashtable<String, Integer> wordsHash = new Hashtable<String, Integer>();
    for (String thisWord : words)
    {
        if (wordsHash.containsKey(thisWord))
        {
            wordsHash.put(thisWord, wordsHash.get(thisWord) + 1);
        }
        else
        {
            wordsHash.put(thisWord, 1);
        }
    }
    Integer mostPopularCount = 0;
    String mostPopularWord = null;
    boolean tie = false;
    while (wordsHash.keys().hasMoreElements())
    {
        String currentWord = (String) wordsHash.keys().nextElement();
        if (wordsHash.get(currentWord) > mostPopularCount)
        {
            mostPopularCount = wordsHash.get(currentWord);
            mostPopularWord = currentWord;
            tie = false;
        }
        else if (wordsHash.get(currentWord) == mostPopularCount)
        {
            tie = true;
        }
    }
    if (tie)
        return null;
    else
        return mostPopularWord;
  }
}

你在循环的每次迭代中调用wordsHash.keys() ,这会在每次迭代时给你一个新的Enumeration<String> - 然后你在循环再次调用它。

您想要调用一次 ,然后遍历单个Enumeration<String>

Enumeration<String> iterator = wordsHash.keys();
while (iterator.hasMoreElements())
{
    String currentWord = iterator.nextElement();
    ...
}

请注意,因为您还获得了每个元素的值,所以最好迭代entrySet()而不是keys()

你最好还是使用HashMap而不是Hashtable ,因为你可以使用增强的for循环......

问题是符合的

while (wordsHash.keys().hasMoreElements())

每次循环时,您都会获得枚举的新副本。 您将需要获取一次密钥集,并对其进行迭代。

在这里使用增强的for循环可能更容易

   for (Map.Entry<String,Integer> entry : wordsHash.entrySet()) {
        String currentWord = entry.getKey();
        Integer currentCount = entry.getValue();
        //more code here
    }

这应该提供您想要的行为,同时更简单,更容易阅读。

问题是无论何时调用wordsHash.keys() ,它都会返回一个新的枚举:

while (wordsHash.keys().hasMoreElements())                        // <=== HERE
{
    String currentWord = (String) wordsHash.keys().nextElement(); // <=== AND HERE

您需要做的是创建一个枚举并在整个循环中使用它。

PS你为什么使用Hashtable而不是HashMap

每次调用.keys()返回一个新的枚举,并带有一个用于迭代的新内部指针:

Hashtable table = new Hashtable();
table.put("a", "a");
table.put("b", "b");
boolean b = table.keys() == table.keys();
System.out.println(b); // false
                       // the two calls to `.keys()` returned different instances of Enumeration

因此,将keys枚举分配给变量:

Enumeration keys = wordsHash.keys();
while (keys.hasMoreElements())
{
    String currentWord = (String) keys.nextElement();

}

将您的代码更改为:

Enumeration<String> keys = wordsHash.keys();
while (keys.hasMoreElements()) {
    String currentWord = keys.nextElement();

因此,每次进入循环时都不会创建指向HashTable的第一个键的新枚举。

什么都没有修改wordsHash 这意味着如果wordsHash.keys().hasMoreElements()为真一次,则对于程序的其余部分,它将继续为真。 这会导致无限循环。 您需要在进行时删除密钥,或者只需使用for

你得到一个新的Iterable ofer每个循环迭代的所有键: wordsHash.keys()只要其中至少有一个键,while循环永远不会结束。

更换:

while (wordsHash.keys().hasMoreElements()){
   String currentWord = (String) wordsHash.keys().nextElement();

通过

for (String currentWord: wordsHash.keys()){

此外,与您的枚举问题无关,这可能是一个缺陷:

else if (wordsHash.get(currentWord) == mostPopularCount)

这是java.lang.Integer与另一个java.lang.Integer的参考比较。 它不是它们所代表的实际值的比较。 它适用于“小”数字,因为自动装箱使用缓存的引用,但最终会破坏。 你可能想要:

else if (wordsHash.get(currentWord) == mostPopularCount.intValue())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM