4

我正在尝试使用 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;
  }
}
4

8 回答 8

10

您正在调用wordsHash.keys()循环的每次迭代,这会在每次迭代中为您提供新鲜感- 然后您会在循环Enumeration<String>再次调用它。

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

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

请注意,由于您还获得了每个元素的值,因此最好迭代.entrySet()而不是keys().

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

于 2013-01-30T19:37:14.520 回答
8

问题在排队

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

每次通过循环,您都会获得枚举的新副本。您将希望获得一次密钥集,然后对其进行迭代。

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

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

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

于 2013-01-30T19:36:38.903 回答
6

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

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

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

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

于 2013-01-30T19:36:46.490 回答
2

每次调用都会.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();

}
于 2013-01-30T19:37:33.320 回答
1

将您的代码更改为:

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

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

于 2013-01-30T19:36:53.350 回答
0

没有任何东西可以修改wordsHash. 这意味着如果wordsHash.keys().hasMoreElements()一次为真,它将在程序的其余部分继续为真。这会导致无限循环。您要么需要删除密钥,要么只使用 for

于 2013-01-30T19:36:33.493 回答
0

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

代替:

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

经过

for (String currentWord: wordsHash.keys()){
于 2013-01-30T19:37:27.767 回答
0

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

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

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

else if (wordsHash.get(currentWord) == mostPopularCount.intValue())
于 2013-01-30T19:43:17.540 回答