哈希表和哈希图之间的区别



我正在做两个总和的问题,但我想使用哈希表而不是哈希图。当我将相同的数字放入哈希表和哈希图时。我发现数字和索引在哈希表和哈希图中的位置是不同的。它似乎根据其位和哈希表存储随机顺序存储数字。也许差异是因为哈希函数。我不知道我是否正确。有人可以向我解释一下吗?谢谢! 下面是哈希图代码和输出:

int[] nums = {2, 7, 11, 15,9,1,13};
int target = 9;
int[] result;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
System.out.println(map);

if (map.containsKey(target)) {
System.out.println(map.get(target));
}

输出:

{1=5,2=0,7=1,9=4,11=2,13=6,15=3}
4

下面是哈希表代码和输出:

int[] nums = {2, 7, 11, 15,9,1,13};    

int target = 9;    
int[] result;    
Hashtable<Integer, Integer> table = new Hashtable<>();    
for (int i = 0; i < nums.length; i++) {    
table.put(nums[i], i);} 
System.out.println(table);    

if (table.containsKey(target)) {   

System.out.println(table.get(target));}

输出:

{9=4,7=1,15=3,13=6,2=0,1=5,11=2}
4

差异是由于两个类中 put 方法的实现。以下是我根据JDK 8的观察结果。

哈希表

Hashtable在按位AND的帮助下进行位掩码,然后计算存储索引。FYR 方法实现如下:

public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}

注意已计算的指数

int index = (hash & 0x7FFFFFFF) % tab.length;

传递给 addEntry(( 方法。此方法在发生哈希冲突时执行双重哈希。FYR 代码如下:

private void addEntry(int hash, K key, V value, int index) {
modCount++;
Entry<?,?> tab[] = table;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}

哈希地图

存储实现包含在 putVal(( 方法中。前南斯拉夫联邦代码:

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

由于Java 8在遇到哈希冲突时,对象存储在平衡二叉树中,通过减少查找时间到O(log n(而不是以前的LinkedList存储(Java 7和以前的存储(来增强性能。这与Hashtable处理碰撞的方法明显不同。

HashTable 和 HashMap 尽管主要基于存储的哈希原则,但实现方式完全不同,请记住多线程/并发处理等几种情况。

此外,hashcode(( 方法属于 Object 类并返回对象 ID,您可以通过在 IDE 中放置断点并在调试模式下检查值来检查该 ID。

最新更新