算法(3.4 散列表)
来源:互联网 发布:如何成为黑客 知乎 编辑:程序博客网 时间:2024/06/08 03:51
3.4.1.6 Java 的约定
每种数据类型都需要相应的散列函数,于是Java 令所有数据类型都继承了一个能够返回一个
32 比特整数的hashCode() 方法。每一种数据类型的hashCode()方祛都必须和equals() 方法一
致。也就是说,如果a,equa1s(b) 返回true,那么a.hashCodeO 的返回值必然和b.hashCode()
的返回值相同。相反,如果两个对象的hashCode() 方法的返回值不同,那么我们就知道这两个
对象是不同的。但如果两个对象的hashCode( 方法的返回值相同,这两个对象也有可能不同,
我们还需要用equa1s() 方祛进行判断。请往意,这说明如果你要为自定义的数据类型定义散列函
数,你需要同时重写hashCode() 和equa1sO 两个方法。默认散列丽数会返回对象的内存地址,
但这只适用于很少的情况。Java 为很多常用的数据类型重写了hashCode() 方法(包括String、
Integer.Double,File 和URL)。
3.4.1.7 将hashCode()的返回值转化为一个数组索引
因为我们需要的是数组的索引而不是一个32 位的整数,我们在实现中会将默认的hashCode()方法
和除留余数法结合起来产生一个0 到M-1的整数,方法如下:
private int hash(Key x){
return (x.hashCode() & 0x7fffffff) % M;
}
这段代码会将符号位屏蔽(将一个32 位整数变为一个31位非负整数),然后用除留余数法i
算它除以M 的余数。在使用这样的代码时我们一般会将数组的大小M 取为素数以充分利用原散列(
的所有位。注意: 为了避免混乱,我们在例子中不会使用这种计算方法而是使用表3.4.1所示的1
列值作为替代。
//拉链法class SeparateChainingHashST<Key, Value>{private int N; // 键值对总数private int M;// 散列表的大小private SequentialSearchST<Key, Value>[] st;// 存放链表对象的数组 public SeparateChainingHashST(){ this(997); } public SeparateChainingHashST(int M){ this.M = M ; st = (SequentialSearchST<Key, Value>[])new SequentialSearchST[M]; for(int i=0;i<st.length;i++){ st[i] = new SequentialSearchST(); } } private int hash(Key key){ return (key.hashCode()&0x7fffffff) % M; } public Value get(Key key){ return (Value)st[hash(key)].get((int)key); // return st[hash(key)].get((int)key); } public void put(Key key,Value val){ st[hash(key)].put(key,val); } }
// 线性探测class LinearProbingHashST<Key, Value>{private int N;// 符号表中键值对的总数private int M; // 线性探测表的大小private Key[] keys;// 键private Value[] vals; // 值public LinearProbingHashST(){M = 16;keys = (Key[])new Object[16];vals = (Value[])new Object[16];}public LinearProbingHashST(int M){this.M = M;keys = (Key[])new Object[M];vals = (Value[])new Object[M];}private int hash(Key key){ return (key.hashCode()&0x7fffffff) % M; }private void resize(int cap){LinearProbingHashST<Key, Value> t = new LinearProbingHashST<Key, Value>(cap);for (int i=0; i<M; i++){if (keys[i] != null){t.put(keys[i], vals[i]);}}this.M = cap;this.keys = t.keys;this.vals = t.vals;}public void put(Key key, Value val){if (N >= M/2){resize(2*M);}int i;for (i=hash(key); keys[i]!=null; i=(i+1)%M){if (keys[i].equals(key)){vals[i] = val;return;}}keys[i] = key;vals[i] = val;N++;}public Value get(Key key){for (int i=hash(key); keys[i]!=null; i=(i+1)%M){if (keys[i].equals(key)){return vals[i];}}return null;}//3.4.3.1 删除操作////如何从基于线性探测的散列表中删除一个//键? 仔细想一想,你会发现直接将该键所在的位//置设为null是不行的,因此,我们需要将簇中被删除键的右侧的//所有键重新插入散列表。和拉链祛一样,//开放地址类的散列表的性能也依赖于a=N/M的比值,//但意义有所不同。public void delete(Key key){if (get(key) == null){return;}int i = hash(key);while (!keys[i].equals(key)){i = (i + 1) % M;}keys[i] = null;vals[i] = null;i = (i + 1) % M;while (keys[i] != null){Key k = keys[i];Value v = vals[i];keys[i] = null;vals[i] = null;N--;// 相当于先删除再插入 所以先减少,在插入方法里面会增加put(k, v);;i = (i+1) % M;}N--;if (N > 0 && N == M/8){resize(M/2);}}}
在拉链法中调整散列表大小不是必需的,在线性探测法中调整大小是必需的
阅读全文
0 0
- 算法(3.4 散列表)
- 散列表(哈希表)查找算法
- 散列表(哈希表)查找算法
- 算法导论11(散列表)
- 算法导论---------------散列表(hash table)
- 算法简单笔记(2):散列表
- 散列表(哈希表)查找算法
- 算法学习笔记--散列表(1)
- 算法导论读书笔记(11)散列表
- 算法导论-----散列表
- 《算法》—散列表
- 《算法导论》散列表
- 算法---散列表
- 《算法4》散列表
- 算法-----链接法散列表
- 算法导论之散列表
- 算法导论小结-散列表
- 算法导论—散列表
- 二分查找法
- C++如何确保输出的小数位数——以计算加权平均值为例
- Tomcat配置 https SSL证书
- Anaconda
- Creating cluster [ERR] Node 127.0.0.1:7001 is not configured as a cluster node.
- 算法(3.4 散列表)
- 51nod1127-尺取法-最短的包括字符串
- Tekla.Structures.v2017 1DVD
- 文章标题
- [LeetCode]19. Remove Nth Node From End of List
- Codeforces Round #237 (Div. 2) 404B Marathon【精度】 好题!!!!
- C和C++的一点小区别
- C语言 printf格式控制符 完全解析
- 深入理解LinkedList