比较数组值和 HashMap

Comparing Array Values and HashMap

我正在制作剪刀石头布游戏,我应该将用户的最后四次投掷保存到 HashMap 中。最后四次投掷将在模式 class 内。我有它,如果该模式已经在 HashMap 中,则该值将增加 1,表明用户已重复该模式一次。这些模式将用于预测用户的下一步行动。但是,当我比较两个模式时,HashMap 中的模式和我刚刚传入的模式,即使它们不相同,但 returns 它们是相同的。我已经尝试对此进行了一段时间的调查,但找不到问题所在。一些帮助将不胜感激!错误出现在第二个输入处。如果我输入 R,它会将它保存在 HashMap 中,但是当我输入任何其他内容时,它会抛出 NullPointerException,我认为这是因为新模式未存储在 hashmap 中,但我试图获取它的值,因为程序认为它等于 HashMap 中已有的那个。我认为问题出在 Pattern 中的 equals() 内部,但我不完全确定。

import java.util.*;

public class RockPaperScisors{
  public static void main(String[] args){
    Scanner key = new Scanner(System.in);
    Pattern pattern = new Pattern();
    Pattern pattern1;
    Computer comp = new Computer();
    boolean stop = false;
    int full=0;;
    while ( !stop ){

      System.out.println("Enter R P S. Enter Q to quit.");
      char a = key.next().charAt(0);
      if ( a == 'Q' ){
        stop = true;
        break;
      }
      pattern.newPattern(a);
      char[] patt = pattern.getPattern();

      for ( int i = 0; i < patt.length; i++ ){
        System.out.print(patt[i] + " ");
      }

      pattern1 = new Pattern(patt);
      comp.storePattern(pattern1);

      System.out.println();
      System.out.println("Patterns: " + comp.getSize());
      full++;
    }
  }
}

import java.util.*;

public class Pattern{
  private char[] pattern;
  private int full = 0;

  public Pattern(){
    pattern = new char[4];
  }

  public Pattern(char[] patt){
    pattern = patt;
  }

  public char[] getPattern(){
    return pattern;
  }

  public void newPattern(char p){
    if ( full <= 3 ){
      pattern[full] = p;
      full ++;
    }
    else{
      for (int i = 0; i <= pattern.length-2; i++) {
        pattern[i] = pattern[i+1];
      }
      pattern[pattern.length-1] = p;
    }
  }

  public int HashCode(){
    char[] a = pattern;
    return a.hashCode();
  }

  public boolean equals( Object o ) {
    if( o == this ) {  return true; }
    if(!(o instanceof Pattern)){ return false; }
    Pattern s = (Pattern) o;
    if (Arrays.equals(s.getPattern(), pattern))
      System.out.println("Yes");
    return Arrays.equals(s.getPattern(), pattern);
  }
}

import java.util.*;
import java.util.Map.Entry;

public class Computer{
  private HashMap<Pattern, Integer> map;

  public Computer(){
    map = new HashMap <Pattern, Integer>();
  }

  public void storePattern(Pattern p){
    boolean contains = false;
    for (Entry<Pattern, Integer> entry : map.entrySet())
    {
      Pattern patt = entry.getKey();
      if ( p.equals(patt) ){
        contains = true;
      }
    }
    if ( contains ){
      int time = map.get(p);
      time++;
      map.put(p, time);
    }
    else
      map.put(p, 0);
  }

  public int getSize(){
    return map.size();
  }
}

你的哈希码是错误的。

应该写成小写

 public int hashCode()

为了确保方法被覆盖,使用@Override注解。

Pattern#HashCode中的问题完全有可能。

第一个问题是它没有被使用(应该是Pattern#hashCode),第二个问题是它没有计算你认为的那样

您可能会发现 java.util.Arrays#hashCode 非常有用,将支持从数组更改为 List 也可以。

附带说明一下,Pattern 不是 class 名称的好选择,因为它与 java.util.regex.Pattern 冲突。在这种情况下,这比在其他情况下可能更成问题,因为它可以与 Scanner 一起使用。

正如另一个答案所指出的,要做的第一件事是重命名并注释您的 hashcode() 方法。

然后,你也必须修复它。它使用

char[] a = pattern;
return a.hashCode();

这意味着它使用了 char[] 对象的 hashCode() 函数。但该函数直接继承自 Object,并为两个相等的字符数组提供不同的哈希码。例如,试试这个:

    char[] c = { 'a','b','c' };
    char[] d = { 'a','b','c' };
    System.out.printf("%d %d%n", c.hashCode(), d.hashCode());

你会看到它打印了两个不同的数字。

所以你需要使用更好的哈希码函数。您可以自己制作或使用 Arrays.hashCode(pattern)(不需要本地 a 变量)。重要的是,当两个Patterns根据equals()方法相等时,它们应该具有相同的哈希码。

在您的情况下,您通过测试所有输入键的相等性来查找 HashCode(我稍后会讲到,这是一件坏事),所以 equals告诉你你在哈希映射中有相同的键。但是hash map本身是使用get()中的hashCode()方法来定位对象的。并且根据hashCode()方法,hash map中没有对象具有相同的key!

因此,当对象相等时,它们必须始终一致。


现在,至于你查找对象的方法:

boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
    Pattern patt = entry.getKey();
    if ( p.equals(patt) ){
        contains = true;
    }
}
if ( contains ){
  int time = map.get(p);
  time++;
  map.put(p, time);
} else
  map.put(p, 0);

不是您使用Map的方式。 HashMap 的全部意义在于,您可以在 O(1) 中查看它是否包含某个键。你正在做的是迭代它并比较 - 那是 O(N),非常浪费。

如果你正确地实现了你的 hashCode(),你可以通过执行 map.containsKey(p) 而不是那个循环来查找它。如果你确定你没有在地图中放置空值,你可以简单地使用 get() 来获取你的模式:

Integer time = map.get(p);

if ( time == null ) {
     map.put( p, 0 );
} else {
     map.put( p, time+1);
}

(你不需要使用++,因为你把它放入地图后实际上并没有使用time)。