【问题标题】:How to Develop a Hash function for traffic license numbers?如何开发交通牌照号码的Hash函数?
【发布时间】:2016-04-16 20:28:55
【问题描述】:

开发一个散列函数来为给定的交通许可证号码生成一个介于 0-4999 之间的索引值。您的散列函数应该产生尽可能少的冲突。散列函数应该使用许可证号的属性。哈希方法应该将许可证号作为单个字符串并返回一个索引值。我们假设许可证编号采用以下格式: 城市代码是介于 10 和 99 之间的数字。三个字母是英文字母表中的任意字母组合,有 26 个字符。两位数是 10 到 99 之间的数字。

我写了一些关于这个问题的东西,但是碰撞很多(5k 1800)

    static long printValue(String s) {
    long result = 0;
    for (int i = 0; i < s.length(); i++) {
        result += Math.pow(27, MAX_LENGTH - i - 1) * (1 + s.charAt(i) - 'A');
    }

    result = result % 5009;


    return (int) result;
}

public int hashF(String str) {

    String a = str.substring(0, 2);
    String b = str.substring(5, 7);
    String middle = str.substring(2, 5);

    int q = (int) printValue(middle);

    String last = a + q + b;

    int index = Integer.parseInt(last);
    index = index % 5009;
    return index;




}

Link for orjinal file of licence numbers.

这些是交通许可证号文件中的一些示例。碰撞次数必须为 300(最大值)。

65HNM25 93DTV23 94WPX23 31RKK46 15YXX90 31MDV74 45BOG99 65JRM50 77VXR55 39TKY41 80MJU73 63QYE57 38FCO80 45ORI16 17CHN73 70SXR63 87CVM74 27EEE85 32PFJ91 50PBA66 70TVK72 15YLS20 80MPM74 21ZRN20 36VVE84 58IDW24 77VDC89 19BVK93 28SUF63

【问题讨论】:

  • "三位数字是介于 100 和 999 之间的数字。"我在您的数据集中没有看到任何三位数。
  • "0-4999 之间的索引值" - 您的索引在 0 和 5008 之间!
  • 我编辑了问题。
  • 没错,索引应该是 5000,但是使用素数我们可以减少碰撞。我们可以改变一点。

标签: java data-structures hash hashtable


【解决方案1】:

你的问题不是你的代码,而是数学。甚至是一个(非常适合你,但不是很有用)哈希码,它产生连续的哈希值,然后是 mod 5000,即

10AAA10 -> 0
10AAA11 -> 1
... etc
99ZZZ99 -> 600 (90 * 26 * 26 * 26 * 90) % 5000

统计上会产生超过 1800 次碰撞,并不比最简单的实现更好,即使用 String 的 hashCode:

 int hash = Math.abs(number.hashCode() % 5000);

这是一个愚蠢的练习,因为它在现实世界中没有用处。

【讨论】:

  • 由于数字00-09不允许出现在开头或结尾,因此完美的连续哈希生成将基于(90 * 26 * 26 * 26 * 90) % 5000
【解决方案2】:

您可以将车牌分成 3 部分。但是将中间转换为数字,对其进行哈希处理,然后将两个外部字符串相加,将其全部转换为整数,然后最后对其进行取模……很尴尬。

我会先将前缀 (10-99) 转换为整数,然后减去 10 得到 0-89 的范围。

然后,对于每个字母,我将结果乘以 26,并添加字母的索引 (0-25)。

第三,我将整个结果乘以 90(最后部分的范围),将最后 2 个字符转换为整数,减去 10 将 10-99 范围转换为 0-89,然后添加到之前的结果。

最后,将结果修改为 5000 以达到所需的 0-4999 范围。


伪代码:

result = toInt(prefix) - 10

foreach letter in middle:
    result = result * 26  + ( letter - 'A' )

result = result * 90  +  ( toInt(suffix) - 10)

result = result % 5000

【讨论】:

  • 谢谢。你能举一个第二步的例子吗?
  • 上面的伪代码应该会有所帮助;只需从 printValue 函数中调整现有循环即可。
猜你喜欢
  • 1970-01-01
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多