将字符串映射到整数

时间:2008-12-20 18:27:49

标签: java

Java中将字符串(Java String)映射到(正)整数(Java int)的最简单方法是什么,以便

  • 相等的字符串映射到相等的整数,
  • 不同的字符串映射到不同的整数?

因此,类似于hashCode(),但生成不同的整数需要不同的字符串。因此,从某种意义上说,它将是一个没有碰撞可能性的hasCode()。

一个明显的解决方案是维护从字符串到整数的映射表, 和一个计数器,以保证新字符串被赋予一个新的整数。我是在想 这个问题通常是如何解决的。 将它扩展到除字符串之外的其他对象也很有趣。

10 个答案:

答案 0 :(得分:6)

查看perfect hashing

答案 1 :(得分:4)

不会有简单或完整的解决方案。我们使用哈希,因为有更多可能的字符串而不是整数。碰撞只是使用有限数量的位来表示整数的限制。

答案 2 :(得分:4)

在大多数hashcode()类型的实现中,碰撞被认为是不可避免的并经过测试。

如果绝对必须没有碰撞,那么您提出的解决方案将起作用。

除此之外,还有加密哈希函数,如MD5和SHA,其中冲突极不可能(尽管可以强制进行大量工作)。 Java Cryptography Architecture具有这些实现。对于非常大的集合,这些方法可能比您的解决方案的良好实现更快。它们也将在恒定时间内执行,并为相同的字符串提供相同的代码,无论字符串的添加顺序如何。此外,它不需要存储每个字符串。加密哈希结果可以被视为整数,但它们不适合java int - 您可以使用BigInteger来保存它们,如另一个答案所示。

顺便提一下,如果你因为“极不可能”发生碰撞而被推迟,那么可能会有一种可能性,即你的计算机内存或硬盘会随机翻转并导致任何程序的行为与预期不同:-)

请注意,某些散列函数(例如MD5)也存在一些理论上的缺点,但出于您的目的,可能无关紧要,您可以使用效率最高的函数 - 这些弱点仅在某人恶意尝试时才有意义提出与另一个字符串具有相同代码的字符串。

编辑:我刚刚在你的问题标题中注意到,你似乎想要双向映射,尽管你实际上并没有在问题中说明这一点。它(按设计)不可能从加密哈希到原始字符串。如果你真的需要它,你必须存储一个将哈希键回到字符串的地图。

答案 3 :(得分:4)

这是不可能没有任何限制地实现的,因为有更多可能的字符串而不是整数,所以最终你会用完数字。

只有在限制可用字符串数量时才能使用解决方案。然后你可以使用一个简单的计数器。这是一个简单的实现,其中可以使用所有(2 ^ 32 = 4294967296个不同的字符串)。别介意它占用大量内存。

import java.util.HashMap;
import java.util.Map;

public class StringToInt {

    private Map<String, Integer> map;

    private int counter = Integer.MIN_VALUE;

    public StringToInt() {
        map = new HashMap<String, Integer>();
    }

    public int toInt(String s) {
        Integer i = map.get(s);
        if (i == null) {
            map.put(s, counter);
            i = counter;
            ++counter;
        }
        return i;
    }
}

答案 4 :(得分:3)

我试着通过引入一个包含Map和Map的对象来做。向该对象添加字符串(或者可能从所述对象创建它们)将为它们分配一个Integer值。为已注册的String请求Integer值将返回相同的值。

缺点:不同的启动会为同一个String产生不同的整数,具体取决于顺序,除非你以某种方式坚持整个事情。此外,它不是面向对象的,需要一个特殊的对象来创建/注册一个String。 另外一面:它与内化字符串非常相似,易于理解。 (另外,你要求一种简单而不优雅的方式。)

对于更一般的情况,您可以创建Object的高级子类,在那里引入“integerize”方法并从中扩展每个类。不过,我认为这条道路会让人流泪。

答案 5 :(得分:2)

由于java中的字符串长度无限制,并且每个字符有16位,并且ints有32位,因此如果字符串最多为两个字符,则只能生成字符串到int的唯一映射。但您可以使用BigInteger生成唯一的映射,例如:

String s = "my string";
BigInteger bi = new BigInteger(s.getBytes());

反向映射:

String str = new String(bi.toByteArray());

答案 6 :(得分:1)

您是否可以使用Map来指示您已将整数分配给哪些字符串?这就是“数据库-y”解决方案,您可以在序列中为每个字符串分配一个“主键”。然后将String和Integer对放入Map中,以便再次查找。如果您需要给定Integer的String,您也可以将同一对放入Map中。

答案 7 :(得分:1)

正如您所概述的,解决冲突的哈希表是一种标准解决方案。您还可以使用Bentley / Sedgewick样式搜索trie,在许多应用程序中比搜索更快。

如果您将“唯一指针”替换为“唯一整数”,则可以看到Dave Hanson's solution to this problem in C。这是一个非常好的抽象,因为

  • 指针仍然可以用作C字符串。

  • 相等的字符串哈希到相等的指针,因此可以省略strcmp以支持指针相等,并且指针可以用作其他哈希表中的键。

如果Java在String个对象上提供对象标识测试,那么您可以在那里玩同一个游戏。

答案 8 :(得分:0)

如果用整数表示数据类型,那么正如其他海报所解释的那样,这是不可能的,因为整数数据类型具有固定大小,并且字符串是未绑定的。

但是,如果你只是一个正数,那么理论上你应该能够将字符串解释为一个“整数”,只需将其视为一个字节数组(以一致的编码)。你也可以将它视为一个任意长度的整数数组,但如果你能做到这一点,为什么不只是使用一个字符串? :)

实现说,这通常是通过使用哈希码“简单地”双重检查任何冲突来“解决”,因为无论如何都可能没有,并且在发生冲突的情况下,它仍然可以保持不变时间。但是,如果这不适用,我不确定最佳解决方案是什么。

有趣的问题。

答案 9 :(得分:0)

我不知道这是否可行,但是如果我们仅使用小写字母,那么每个单词在26个基数的位置系统中都可以看作一个数字。例如,如果a为0,z为25,而臂杆为1 * 26 ^ 3 + 14 * 26 ^ 2 + 14 * 26 ^ 1 + 12 * 26 ^ 0 = 27416