股票代码的更好的 hashCode 函数?

Better hashCode function for stock ticker symbols?

我将库存对象保存在 HashMap 中,其中键是股票代码 String(例如 "AAPL" 代表 Apple, Inc.)。不幸的是,这是不可行的,因为 Ally Financial Inc (GM1) 和 Global Partners LP (GLP) 具有冲突的哈希码并且会相互覆盖。例如:"GM1".hashCode() == "GLP".hashCode() == 主要问题。

是否有 hashCode 可以保证不冲突的股票代码字符串?

public Class StockTicker {
    public String symbol;

    public StockTicker(String symbol) { this.symbol = symbol; }

    @Override
    public int hashCode() {
        // What goes here?
    }
}

成功的答案可能会利用以下事实:股票代码字符串将不超过 5 个字符,并且将是除“.”之外的大写字母数字。如 "BRK.B".

我认为键字符串的 hashCode 对地图本身没有任何影响(我假设您使用的是键的实际股票代码字符串,而不是哈希码;如果您插入到地图中使用哈希码,那么是的,这会导致问题)。我 运行 进行了快速测试,运行良好。

private Map<String, String> stockMap = new HashMap<String, String>();

@Test
public void mapTest() {
    stockMap.put("GM1", "gm1stock");
    stockMap.put("GLP", "glpstock");

    assertEquals(2, stockMap.size());
}

正如 Mshnik 所说,Java 会为您处理碰撞,因此您无需担心。您能否详细说明具体是什么代码导致了您的问题?

正如其他答案和评论所指出的那样,A) Java 将正确处理冲突,前提是您已经以令人满意的方式编写了 equals 和 hashcode,并且 B) 即使获得完美的 hashcode 函数也不能保证这样你就不会发生碰撞。

话虽如此,可以为您的规范编写完美的哈希码函数。您需要担心的字符正好有 37 个(26 个字母、10 个数字和 .),少于 64 个。因此我们可以使用 6 位来表示每个字符。您最多有 5 个字符,这意味着您的哈希码最多需要 30 位,适合一个 int。

这是创建完美哈希码的实现:

  public static class Stock{
    // The possible characters of a stock - note length is < 64
    private final static String alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.";

    //Will be 6 for given valid chars, but coding it like this prevents bugs later
    private final static int shiftAmnt = (int)(Math.log(alphaNumeric.length()) / Math.log(2)) + 1;

    private String stock;

    public Stock(String s) {
      stock = s;
    }

    @Override
    public boolean equals(Object o) {
      return o instanceof Stock && stock.equals( ((Stock)o).stock);
    }

    @Override
    public int hashCode() {
      int code = 0;
      for (char c : stock.toCharArray()) {
        code = code << shiftAmnt;
        code += alphaNumeric.indexOf(c);
      }
      return code;
    }
  }