我一直在尝试在业余时间学习C语言,其他语言(C#,Java等)具有相同的概念(通常是相同的运算符)......
我想知道是,在核心层,是什么位移(<<,>>,>>>)这样做,可以帮助它什么问题解决,和周围的弯曲什么潜伏的陷阱?换句话说,一个绝对的初学者指导比特移位的所有优点.
每Java文档中,哈希代码的String对象被计算为:
Run Code Online (Sandbox Code Playgroud)s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]使用
int算术,其中s[i]是 字符串的第i个字符,是字符串n的长度,并^指示取幂.
为什么31用作乘数?
我知道乘数应该是一个相对较大的素数.那么为什么不是29岁,37岁,甚至97岁?
很久以前,我以1.25美元的价格从交易台上买了一本数据结构书.在其中,哈希函数的解释说,由于"数学的本质",它最终应该由质数修改.
你对1.25美元的书有什么期望?
无论如何,我有多年的时间来思考数学的本质,但仍然无法弄明白.
当存在大量的桶时,数字的分布是否真的更均匀?或者这是一个老程序员的故事,每个人都接受,因为其他人都接受它?
什么是正确和好的实施方式__hash__()?
我在谈论返回哈希码的函数,该哈希码随后用于将对象插入哈希表,即字典.
当__hash__()返回一个整数并用于将对象"分箱"为哈希表时,我假设返回的整数的值应该为公共数据均匀分布(以最小化冲突).获得这些价值观的好习惯是什么?碰撞是一个问题吗?在我的例子中,我有一个小类,它充当一个容器类,包含一些int,一些浮点数和一个字符串.
类Boolean的hashCode()方法实现如下:
public int hashCode() {
return value ? 1231 : 1237;
}
Run Code Online (Sandbox Code Playgroud)
为什么使用1231和1237?为什么不是别的?
我有一个整数的2D数组.我希望将它们放入HashMap中.但我想基于Array Index访问HashMap中的元素.就像是:
对于A [2] [5],map.get(2,5)它返回与该键相关联的值.但是如何使用一对键创建hashMap?或者一般来说,多个键:Map<((key1, key2,..,keyN), Value)我可以使用get(key1,key2,... keyN)访问元素.
编辑:发布问题3年后,我想补充一点
我遇到了另一种方式NxN matrix.
数组索引,i和j可被表示为一个单一的key方式如下:
int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key);
Run Code Online (Sandbox Code Playgroud)
并且可以通过key以下方式从这些指数中恢复指数:
int i = key / N;
int j = key % N;
Run Code Online (Sandbox Code Playgroud) Eclipse 3.5有一个非常好的功能来生成Java hashCode()函数.它会产生例如(稍微缩短:)
class HashTest {
int i;
int j;
public int hashCode() {
final int prime = 31;
int result = prime + i;
result = prime * result + j;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
(如果类中有更多属性,result = prime * result + attribute.hashCode();则对每个附加属性重复.对于int.可以省略.hashCode().)
这似乎很好,但选择31为素数.它可能来自Java String的hashCode实现,它被用于性能原因,这些原因在引入硬件乘法器之后很久就消失了.对于i和j的小值,这里有许多哈希码冲突:例如(0,0)和(-1,31)具有相同的值.我认为这是一个Bad Thing(TM),因为经常出现小值.对于String.hashCode,您还会发现许多具有相同哈希码的短字符串,例如"Ca"和"DB".如果选择大素数,如果选择素数,此问题就会消失.
所以我的问题是:选择什么是好的素数?你用什么标准来找到它?
这是一个普遍的问题 - 所以我不想给i和j一个范围.但我认为在大多数应用中,相对较小的值比较大的值更常出现.(如果你有大的值,素数的选择可能不重要.)它可能没有多大区别,但更好的选择是一种简单明了的方法来改善这一点 - 那么为什么不这样做呢?Commons lang HashCodeBuilder也提出了奇怪的小值.
(澄清:这不是重复为什么String中的Java的hashCode()使用31作为乘数?因为我的问题不关心JDK中31的历史,而是关于新代码中更好的值使用相同的基本模板.没有任何答案试图回答.)
我已经用Netbeans开发了一段时间的Java,并且有些事情我只是依赖于工作而没有真正质疑如何.其中包括自动生成的hashCode()和equals()方法.
equals方法很容易遵循,但我发现hashCode方法有些神秘.我不明白为什么它选择乘数并应用它所做的操作.
import java.util.Arrays;
import java.util.Objects;
public class Foo {
int id;
String bar;
byte[] things;
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + this.id;
hash = 89 * hash + Objects.hashCode(this.bar);
hash = 89 * hash + Arrays.hashCode(this.things);
return hash;
}
}
Run Code Online (Sandbox Code Playgroud)
搜索文档,这个网站和谷歌搜索"netbeans生成哈希码"之类的内容,似乎没有任何相关内容.有谁在这里熟悉这一代策略是什么以及为什么Netbeans使用它?
编辑:
感谢您的答案到目前为止!特别是由于对链接的SO问题的这个答案,我理解现在更充分地使用素数来设计hashCode方法的逻辑.然而,到目前为止我没有真正解决的问题的另一个方面是Netbeans如何以及为什么选择它为其生成的方法所做的素数.的hash字段,另一个乘法器(89在我的例子)似乎取决于类的各种因素是不同的.
例如,如果我String在类中添加第二个,则hashCode()变为
public int hashCode() {
int hash = 7;
hash = 13 * hash + this.id;
hash = 13 …Run Code Online (Sandbox Code Playgroud) 我知道有一种散列技术应用于一个键,用于将其值存储在内存地址中.
但是我不明白碰撞是怎么发生的?Java使用哪种哈希算法来创建内存空间?是MD5吗?
假设我有以下课程:
class ABC {
private int myInt = 1;
private double myDouble = 2;
private String myString = "123";
private SomeRandomClass1 myRandomClass1 = new ...
private SomeRandomClass2 myRandomClass2 = new ...
//pseudo code
public int myHashCode() {
return 37 *
myInt.hashcode() *
myDouble.hashCode() *
... *
myRandomClass.hashcode()
}
}
Run Code Online (Sandbox Code Playgroud)
这是hashCode的正确实现吗?这不是我通常这样做的方式(我倾向于遵循Effective Java的指导方针),但我总是有诱惑去做类似上面代码的事情.
谢谢