[英]Regarding HashMap implementation in java
我试图对 hashmap 进行研究并提出以下分析:
Q1 你们能不能给我看一张简单的地图,你可以在其中展示过程..如何使用这个公式详细计算给定键的哈希码..计算位置哈希%(arrayLength-1))应该放置元素(桶号),假设我有这个 hashMap
HashMap map=new HashMap();//HashMap key random order.
map.put("Amit","Java");
map.put("Saral","J2EE");
Q2 有时可能会发生 2 个不同对象的 hashCode 相同的情况。 在这种情况下,2 个对象将保存在一个存储桶中,并将显示为 LinkedList。 入口点是最近添加的对象。 这个对象是指具有下一个字段等的其他对象。 最后一个条目指的是 null。 你们能用真实的例子告诉我这个吗..!!
.
“Amit”将被分配到第 10 个桶中,因为有点麻烦。 如果没有一点点麻烦,它会进入第 7 个桶,因为 2044535 & 15 = 7。这怎么可能,请详细解释整个计算..?
快照已更新...
另一个图像是......
如何使用此公式详细计算给定键的哈希码
在String
情况下,这是通过String#hashCode();
计算的String#hashCode();
其实现如下:
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
基本上遵循java doc中的方程
hashcode = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
在这个实现中需要注意的一件有趣的事情是String
实际上缓存了它的哈希码。 它可以做到这一点,因为String
是不可变的。
如果我计算String
“Amit”的哈希码,它将产生这个整数:
System.out.println("Amit".hashCode());
> 2044535
让我们通过一个简单的放置到地图,但首先我们必须确定地图是如何构建的。 Java HashMap
最有趣的事实是它总是有 2^n 个桶。 所以如果你调用它,桶的默认数量是16,显然是2^4。
在这个映射上做一个放置操作,它首先会得到键的哈希码。 在这个哈希码上发生了一些花哨的位处理,以确保糟糕的哈希函数(尤其是那些在低位没有不同的函数)不会“超载”单个存储桶。
实际负责将您的密钥分发到存储桶的真正功能如下:
h & (length-1); // length is the current number of buckets, h the hashcode of the key
这仅适用于两个桶大小的幂,因为它使用 & 将键映射到桶而不是模数。
“Amit”将被分配到第 10 个桶中,因为有点麻烦。 如果没有一点乱动,它将进入第 7 个桶,因为2044535 & 15 = 7
。
现在我们有了它的索引,我们可以找到存储桶。 如果桶包含元素,我们必须迭代它们并在找到它时替换相等的条目。 如果在链表中没有找到任何项目,我们将把它添加到链表的开头。
HashMap
的下一个重要事情是调整大小,因此如果地图的实际大小超过阈值(由当前的桶数和负载因子决定,在我们的例子中为 16*0.75=12),它将调整支持数组的大小. Resize 总是 2 * 当前的桶数,保证是 2 的幂,不会破坏查找桶的功能。
由于桶的数量发生变化,我们必须重新散列表中的所有当前条目。 这是相当昂贵的,所以如果你知道有多少项,你应该用这个计数初始化HashMap
,这样它就不必一直调整大小。
Q1:查看String
对象的hashCode()
方法实现
Q2:创建简单的类并将其hashCode()
方法实现为return 1
。 这意味着具有该类的每个对象都将具有相同的 hashCode,因此将保存在 HashMap 中的同一存储桶中。
了解哈希码有两个基本要求:
如何实现这些目标是从事此类工作的数学书呆子们非常感兴趣的主题,但了解细节对于了解哈希表的工作原理并不重要。
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
Map<Integer, String> map = new Map<Integer, String>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
map.put(5, "E");
System.out.println("Iterate");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
System.out.println("Get-> 3");
System.out.println(map.get(3));
System.out.println("Delete-> 3");
map.delete(3);
System.out.println("Iterate again");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
}
}
class Map<K, V> {
private int size;
private Entry<K, V>[] entries = new Entry[16];
public void put(K key, V value) {
boolean flag = true;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
entries[i].setValue(value);
flag = false;
break;
}
}
if (flag) {
this.ensureCapacity();
entries[size++] = new Entry<K, V>(key, value);
}
}
public V get(K key) {
V value = null;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
value = entries[i].getValue();
break;
}
}
return value;
}
public boolean delete(K key) {
boolean flag = false;
Entry<K, V>[] entry = new Entry[size];
int j = 0;
int total = size;
for (int i = 0; i < total; i++) {
if (!entries[i].getKey().equals(key)) {
entry[j++] = entries[i];
} else {
flag = true;
size--;
}
}
entries = flag ? entry : entries;
return flag;
}
public int size() {
return size;
}
public Entry<K, V>[] values() {
return entries;
}
private void ensureCapacity() {
if (size == entries.length) {
entries = Arrays.copyOf(entries, size * 2);
}
}
@SuppressWarnings("hiding")
public class Entry<K, V> {
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Entry(K key, V value) {
super();
this.key = key;
this.value = value;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.