如果我有一个类myhashmap,它扩展了hashmap,然后我重写函数hash以返回一个常量,那么我的地图中的插入和查找是如何受到影响的?
答案 0 :(得分:2)
完全没有。您可以在Myhashmap
中覆盖的唯一内容是hashCode()
本身的Myhashmap
。这不会影响Myhashmap
if的性能。另一方面,HashSet<Myhashmap>
和Map<Myhashmap, ?>
会表现得非常糟糕。
要理解这一点,您必须了解HashSet
(或HashMap
的基本功能,但原理是相同的)。两者都是通过根据哈希值将Object
分配到存储桶中来实现的:
List<T>[] buckets = new List<>[bucketnum];
void add(T t){
List<T> l = buckets[t.hashCode() % buckets.length];
if(!l.contains(t))
l.add(t);
}
虽然这个实现过于简单并且不应该在实际代码中使用,但它清楚地表明了一件事:HashSet
很快,因为它使用了桶。但是,使hashCode()
- 方法返回常量将导致HashSet
,其中所有值都插入到单个存储桶中。换句话说:只需抛弃HashSet
并使用List
,因为在最好的情况下运行时根本不会发生变化,或者甚至可能更糟糕,因为{{1}与HashSet/-Map
相比,引入了开销。例如。如果达到某个负载因子,List
会增加桶数,这需要额外的资源。
编辑:
这有点深入,虽然它有趣,因为它显示了HashSet/-Map
的不同实现,但它没有必要理解,因为它只是一个扩展以上对哈希数据结构的介绍应该被视为脚注。实际上还有另一种选择:Collision resolution。在这种情况下,不存在HashSet/-Map
来存储共享某个哈希桶的对象。相反,算法以特定模式搜索可用桶。这可能是线性的,二次的等等。
E.g:
List
此代码使用线性碰撞策略来处理碰撞哈希(两个对象T[] buckets;
boolean add(T t){
int index = t.hashCode() % bucketnum;
for(int i = 0; i < bucketnum; i++){
if(buckets[(i + index) % bucketnum] == null){
buckets[(i + index) % bucketnum] = t;
return true;
}
}
return false;
}
,a
,这样b
)。虽然此实现显示了一些不同的行为并且需要不同的负载因子,但仍然需要适当的散列函数,否则性能将比使用桶列表方法更差。
答案 1 :(得分:0)
在哈希函数中返回常量值没有意义。如果这样做,hashMap将变成简单的链表。
tab[i = (n - 1) & hash]
这里n是地图的大小。
如果你的哈希值是常量,那么它的结果总是不变的,而get / put函数需要花费O(N)时间。