在stackoverflow和web中有几个主题,我无法清楚地理解它们。我在尼克拉斯的堆栈流程中找到了这个答案,他的代表性让我对这个主题有了一些有意义的见解。
key.hashCode()
|
| 32-bit value
| hash table
V +------------+ +----------------------+
HashMap.hash() ----+ | reference | -> | key1 | value1 | null |
| |------------| +----------------------+
| | null |
| offset |------------| +---------------------+
+--------> | reference | -> | key1 | value1 | ref |
|------------| +---------------------+
| .... | |
+----------------+
V
+----------------------+
| key2 | value2 | null |
+----------------------+
What hashing function does Java use to implement Hashtable class?
Map aMap = new HashMap();
aMap.put(key,value);
任何人都可以一步一步地重新解释上面的图表。我无法理解HashMap背后的哈希机制。
答案 0 :(得分:5)
首先,让我解释一下哈希搜索的想法:
让您有一些搜索关键。例如,key只是文本字符串,如“hello”。
让我们为这个字符串计算一些“校验和” - 举个简单的例子 将符号的ASCII码加在一起。让我们(例如,我实际上没有计算) 这笔钱是1009。
让我们拥有固定大小的数组,例如,SZ = 10。将此数组命名为“hash_table”。 每个数组元素都包含BUCKET - 这是一组可能的键。
因此,我们可以通过以下方式计算OFFSET - 数组中的索引,即哈希表:
偏移=总和%SZ = 1009%10 = 9;
让我们通过以下方式将“hello”这个词存入街头车#9中。
hash_table [9] .add_to_list( “你好”);
在那里,我们只有单个键“hello”,存储在单元格hash_table [9];
想象一下,需要插入第二个键,例如“world”。让我们计算总和,它 将再次计算偏移= 37%10 = 7.因此,通过该算法,我们存入 将“世界”改为哈希表[7]。
碰撞。想象一下,你决定添加第三个字键,“碰撞”让这个单词的总和为3007.当你计算偏移时,它将是7.因此,单词“collision”必须存入桶中,其中已经存在的单词“世界”。还行吧。您只需将带有世界“碰撞”的元素添加到链接列表(头部或尾部)中。所以:
哈希表[7] - > “世界” - > “collistion” - >空值; 哈希表[9] - > “你好” - > NULL;
当您需要搜索“hello”键时,再次计算校验和,它再次为1009.此后,您计算offset = 9,然后直接转到#9桶。并且,迭代链接列表,在那里你会找到你的单词“你好”。 “世界”或“碰撞”的类似情况。
当您搜索表格中省略的单词时,您将转到空桶或不包含密钥的存储桶。所以,搜索不成功。
如果你使哈希表太宽(例如,大小与你的字典相同),平均桶大小将是~1个元素(如果哈希函数具有良好的传播)。因此,搜索密钥会很快 - 只需计算hashsum,转到存储桶,并在存储桶中迭代1-2个元素。
第二 - 我会回答你的问题:
偏移 - 只是数组中的索引。数组是一个“哈希表”。每个数组元素都包含指向链表的指针,包含存储在同一存储桶中的密钥。
哈希表 - 只是数组,包含指向存储桶头的指针。使用另一种散列方案(例如,多次散列等) - 它可以包含自己的对象,而不包含链接列表。