Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 顺序无关散列算法_Java_Algorithm_Hash_Set - Fatal编程技术网

Java 顺序无关散列算法

Java 顺序无关散列算法,java,algorithm,hash,set,Java,Algorithm,Hash,Set,我目前正在为我的自定义编程语言开发一个集合库。我已经有了几种数据类型(Collection、List、Map、Set)和它们的实现(可变和不可变),但到目前为止我缺少的是hashCode和equals。由于列表是有序集合,所以这些对列表来说没有问题,但对于集合和映射来说,它们扮演着特殊的角色。如果两个集合具有相同的大小和相同的元素,则认为它们相等,并且集合保持它们相等的顺序不应影响它们的相等性。由于equals hashCode契约,hashCode实现也必须反映这种行为,这意味着具有相同元素但

我目前正在为我的自定义编程语言开发一个集合库。我已经有了几种数据类型(Collection、List、Map、Set)和它们的实现(可变和不可变),但到目前为止我缺少的是
hashCode
equals
。由于列表是有序集合,所以这些对列表来说没有问题,但对于集合和映射来说,它们扮演着特殊的角色。如果两个集合具有相同的大小和相同的元素,则认为它们相等,并且集合保持它们相等的顺序不应影响它们的相等性。由于equals hashCode契约,hashCode实现也必须反映这种行为,这意味着具有相同元素但顺序不同的两个集合应该具有相同的hash代码。(这同样适用于地图,从技术上讲,地图是一组键值对)

示例(伪代码):

让set1:Set=[“a”、“b”、“c”]
设set2:Set=[“b”,“c”,“a”]
set1==set2//应返回true
set1.hashCode==set2.hashCode//也应返回true

如何实现一个相当好的散列算法,使上例中的
hashCode
s返回相同的值?

以下是可能实现的伪代码:

String hashCode = null;
for(element : elements){
    hashCode = xor(hashCode, getHashCode(element));
}
return hashCode;
xor
函数应返回与两个参数中最长的字符串一样长的字符串。它将对每个参数中的位进行异或运算,直到到达其中一个参数的末尾。然后,它将从较长的字符串中提取剩余的位,并将这些位附加到上


这个实现意味着一个集合的hashCode与它最长元素的hashCode一样长。因为要对位进行XOR运算,所以不管元素的顺序如何,哈希代码最终都是相同的。但是,与任何散列实现一样,都有可能发生冲突。

JDK本身提出了以下解决方案。接口合同规定:

返回此集合的哈希代码值。集合的哈希代码定义为集合中元素的哈希代码之和,其中空元素的哈希代码定义为零。这确保了s1.equals(s2)意味着s1.hashCode()==s2.hashCode()对于任意两个集合s1和s2,这是Object.hashCode()的通用合同所要求的

使用条目的哈希代码之和的替代方法是使用,例如,
^
(XOR)运算符


Scala语言使用算法的排序不变版本(参见私有类)来实现its和类似集合的
hashCode
(或
##
)方法。

您可以按字母顺序计算对集合排序的哈希和

这里有一个C#示例-我希望您能用Java翻译它:)

静态字符串GetHash(列表l)
{
使用(System.Security.Cryptography.MD5 MD5=System.Security.Cryptography.MD5.Create())
{
返回BitConverter.ToString(md5.ComputeHash(l.OrderBy(p=>p).SelectMany(s=>System.Text.Encoding.ASCII.GetBytes(s+(char)0)).ToArray())。替换(“-”,”);
}
}

集合中的一对术语(和、积)如何?就我所见,对于不同的数字集来说,这两种方法并不常见。例如,类似于
(e1.hashCode()+e2.hashCode()+…+en.hashCode())^(e1.hashCode()*e2.hashCode()*…*en.hashCode())
?您是否尝试过看看Java是如何实现的?刚刚做了,它对元素的
hashCode
求和“和的散列”和“散列的和”之间有很大的区别。如你的例子所示,前者是有问题的。如果单个散列在大范围内分布良好,则后者的问题较少。但是,当我需要
int
hashCode时,如何使用
String
?这似乎是一个非常灵活的解决方案。@Clashsoft我不确定您想要的是
int
还是
String
。如果它只是一个int,那么获取各个元素的hashcode之和将得到您所需要的,只要溢出环绕而不是导致错误。如果溢出导致错误,则需要显式处理该情况并手动包装。同样的概念。谢谢你的回答,但我想找到一个不同的解决方案,而不是对元素的哈希代码求和(参见注释)。@Clashsoft-请注意,[1,4]是否会与[2,3]冲突,这实际上取决于你对哈希数的实现。记住,您是对数字的散列求和,而不是对数字求和。此外,尽管字符串实现的资源更为密集,但这也意味着它在散列中有更多的位,因此发生冲突的可能性更小。通常,整数的散列码(如果不是超级安全的话)就是整数本身。所以
1.hashCode==1
。另外,由于
hashCode
被强制为
int
,我最终还是要使用
string.hashCode
。正如我在评论中所说的,我已经找到了这个问题的JDK解决方案,但我想知道更有用的无序集合哈希算法,冲突可能性更小。@Clashsoft冲突可能性是多少?如果单个哈希代码中只有一个工作正常,则整个哈希算法将均匀分布。@b很遗憾,结果并不一致@augurar实数和32位有符号整数之间有非常重要的区别。这是其中之一。编写
java.set.Util
的人知道他们在做什么,并在这里提出了一个好的策略。Scala的排序不变哈希仅基于元素哈希的和、积(不包括零)、计数和异或,因此它不像“排序不变的哈希算法版本”那样具有抗冲突性听起来很像。这比只对散列求和要好,但仍然不行
String hashCode = null;
for(element : elements){
    hashCode = xor(hashCode, getHashCode(element));
}
return hashCode;
static String GetHash(List<String> l)
{
    using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
    {
        return BitConverter.ToString(md5.ComputeHash(l.OrderBy(p => p).SelectMany(s => System.Text.Encoding.ASCII.GetBytes(s + (char)0)).ToArray())).Replace("-", "");
    }
}