2008-12-20 99 views
10

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

  • 等于字符串映射平等的整数,和
  • 不同的字符串映射到不同的整数?

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

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

+0

我不知道为什么你想Integer通过toString()轻松地将字符串映射到字符串,反之亦然使用Integer.valueOf()所以有什么意义? – cletus 2008-12-20 18:31:21

+1

@cletus:使用Integer.valueOf(),“Hello”不容易映射为整数。 – 2008-12-20 18:32:29

+0

那么测试问题的有效性部分呢?这个问题确实需要重申和/或澄清。它没有任何意义。 – cletus 2008-12-20 18:35:40

回答

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

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

1

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

2

由于java中的字符串的长度是无限的,并且每个字符都有16位,并且整数有32位,所以如果字符串最多为两个字符,则只能生成字符串的唯一映射。但是你可以使用的BigInteger产生一个唯一的映射,喜欢的东西:

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

反向映射:

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

我会尝试通过引入对象拿着地图和地图做。将字符串添加到该对象(或者可能让它们从所述对象创建)将为它们分配一个整数值。为已经注册的字符串请求整数值将返回相同的值。

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

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

0

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

但是,如果你只是一个正数,那么理论上你应该能够将字符串看作是一个“整数”,只需将它看作一个字节数组(以一致的编码方式)即可。你也可以把它当作一个任意长度的整数数组,但是如果你可以这样做,为什么不使用一个字符串呢? :)

执行说话,这通常是通过使用哈希代码和简单地检查任何冲突“解决”,因为有可能没有任何冲突,并在碰撞的机会,它仍然工作时间不变。但是,如果这不适用,我不确定最好的解决方案是什么。

有趣的问题。

4

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

如果您绝对必须没有碰撞,保证,您概述的解决方案将工作。

除此之外,还有加密散列函数,如MD5和SHA,其中冲突极不可能(尽管可以强制执行很多努力)。 Java密码体系结构具有这些实现。这些方法可能比为您的解决方案实现非常大的集合更好。它们也会在固定时间内执行,并为相同的字符串提供相同的代码,而不管字符串以何种顺序添加。并且,它不需要存储每个字符串。加密哈希结果可以被认为是整数,但它们不适合java int - 你可以使用BigInteger来保存它们,正如另一个答案中的建议。顺便说一句,如果你因为碰撞'非常不可能'的想法而被推迟,那么在你的计算机内存或硬盘上随机翻转并导致任何程序的行为与你不同的可能性相似期望:-)

注意,在一些散列函数(例如MD5)中也存在一些理论上的弱点,但为了您的目的可能无所谓,您可以使用最有效的这种函数 - 这些弱点仅与相关如果有人恶意试图想出与另一个字符串具有相同代码的字符串。

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

1

正如您概述的那样,解决冲突的散列表是一个标准解决方案。您也可以使用Bentley/Sedgewick风格的搜索特征,在许多应用程序中,搜索特征比散列更快。

如果您将'唯一指针'替换为'唯一整数',您可以看到Dave Hanson's solution to this problem in C。这是一个相当不错的抽象,因为

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

  • 等号字符串散列到等号指针,所以strcmp可以免去有利于指针相等,并且指针可以用作其他散列表中的密钥。

如果Java程序String对象提供测试对象的身份,那么你可以在那里玩同一游戏。