哈希表总结
来源:互联网 发布:mobi for mac 编辑:程序博客网 时间:2024/06/13 12:12
1. 哈希表和哈希地址定义
解析:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映像到一个有限的连续的地址集(区间)上,并以
关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为哈希表,这一映像过程称为哈希造表或散列,所
得存储位置称哈希地址或散列地址。
2. 哈希函数构造方法
解析:
(1)直接定址法:取关键字或关键字的某个线性函数值为哈希地址。即。其中,a和
b为常数。
(2)数字分析法:假设关键字是以为基的数,并且哈希表中可能出现的关键字都是事先确定的,则可取关键字的若
干数位组成哈希地址。
(3)平方取中法:取关键字平方后的中间几位为哈希地址。这是一种较常用的构造哈希函数的方法。通常在选定哈
希函数时不一定能知道关键字的全部情况,取其中哪几位也不一定合适,而一个数平方后的中间几位数和数的每一位
都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定。
(4)折叠法:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去
进位)作为哈希地址,这方法称为折叠法。在折叠法中数位叠加可以有移位叠加和间界叠加两种方法。移位叠加是将
分割后的每一部分的最低位对齐,然后相加;间界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。关键字
位数很多,而且关键字中每一位上数字分布大致均匀时,可以采用折叠法得到哈希地址。
(5)除留余数法:取关键字被某个不大于哈希表表长m的树p除后所得余数为哈希地址。即
。除关键字直接取模外,也可在折叠、平方取中等运算之后取模。
(6)随机数法:选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random
为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较恰当。
说明:构造哈希函数需要考虑的因素:计算哈希函数所需时间(包括硬件指令的因素);关键字的长度;哈希表的大
小;关键字的分布情况;记录的查找频率。
3. 处理哈希地址冲突方法
解析:
(1)开放定址法:。其中,H(key)为哈希函数;m为哈希表表
长;为增量序列。(1),称线性探测再散列;(2),
称二次探测再散列;(3)伪随机数序列,称伪随机探测再散列。
(2)再哈希法:。均是不同的哈希函数,即在同义词产生地址冲突时计算另一个哈
希函数地址,直到冲突不再发生。这种方法不易产生“聚集”,但增加了计算的时间。
(3)链地址法:将所有关键字为同义词的记录存储在同一线性链表中。假设某哈希函数产生的哈希地址在区间[0,m-
1]上,则设立一个指针型向量Chain ChainHash[m];其每个分量的初始状态都是空指针。凡哈希地址为i的记录都插入
到头指针为ChainHash[i]的链表中。在链表中的插入位置可以在表头或表尾;也可以在中间,以保持同义词在同一线
性链表中按关键字有序。
(4)建立一个公共溢出区:假设哈希函数的值域为[0,m-1],则设向量HashTable[0..m-1]为基本表,每个分量存放一
个记录,令设立向量OverTable[0..v]为溢出表。所有关键字和基本表中关键字为同义词的记录,不管它们由哈希函数
得到的哈希地址是什么,一旦发生冲突,都填入溢出表。
3. 链地址法
(1)链地址法数据结构
public class SeparateChainingHashST<Key, Value> { private static final int INIT_CAPACITY = 4; private int n; // number of key-value pairs private int m; // hash table size private SequentialSearchST<Key, Value>[] st; // array of linked-list symbol tables ......}
说明:n表示键值对总数,m表示散列表的大小,st表示存放链表对象的数组。
(2)插入操作
public void put(Key key, Value val) { if (key == null) throw new IllegalArgumentException("first argument to put() is null"); if (val == null) { delete(key); return; } // double table size if average length of list >= 10 if (n >= 10 * m) resize(2 * m); int i = hash(key); if (!st[i].contains(key)) n++; st[i].put(key, val);}(3)查找操作
public Value get(Key key) { if (key == null) throw new IllegalArgumentException("argument to get() is null"); int i = hash(key); return st[i].get(key);}(4)删除操作
public void delete(Key key) { if (key == null) throw new IllegalArgumentException("argument to delete() is null"); int i = hash(key); if (st[i].contains(key)) n--; st[i].delete(key); // halve table size if average length of list <= 2 if (m > INIT_CAPACITY && n <= 2 * m) resize(m / 2);}(5)重置哈希表大小
private void resize(int chains) { SeparateChainingHashST<Key, Value> temp = new SeparateChainingHashST<Key, Value>(chains); for (int i = 0; i < m; i++) { for (Key key : st[i].keys()) { temp.put(key, st[i].get(key)); } } this.m = temp.m; this.n = temp.n; this.st = temp.st;}
4. 线性探测法
(1)线性探测法数据结构
public class LinearProbingHashST<Key, Value> { private static final int INIT_CAPACITY = 4; private int n; // number of key-value pairs in the symbol table private int m; // size of linear probing table private Key[] keys; // the keys private Value[] vals; // the values ......}
说明:n表示符号表中键值对的总数,m表示线性探测表的大小,keys表示键,vals表示值。
(2)插入操作
public void put(Key key, Value val) { if (key == null) throw new IllegalArgumentException("first argument to put() is null"); if (val == null) { delete(key); return; } // double table size if 50% full 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++;}(3)查找操作
public Value get(Key key) { if (key == null) throw new IllegalArgumentException("argument to get() is null"); for (int i = hash(key); keys[i] != null; i = (i + 1) % m) if (keys[i].equals(key)) return vals[i]; return null;}(4)删除操作
public void delete(Key key) { if (key == null) throw new IllegalArgumentException("argument to delete() is null"); if (!contains(key)) return; // find position i of key int i = hash(key); while (!key.equals(keys[i])) { i = (i + 1) % m; } // delete key and associated value keys[i] = null; vals[i] = null; // rehash all keys in same cluster i = (i + 1) % m; while (keys[i] != null) { // delete keys[i] an vals[i] and reinsert Key keyToRehash = keys[i]; Value valToRehash = vals[i]; keys[i] = null; vals[i] = null; n--; put(keyToRehash, valToRehash); i = (i + 1) % m; } n--; // halves size of array if it's 12.5% full or less if (n > 0 && n <= m / 8) resize(m / 2); assert check();}(5)重置哈希表大小
private void resize(int capacity) { LinearProbingHashST<Key, Value> temp = new LinearProbingHashST<Key, Value>(capacity); for (int i = 0; i < m; i++) { if (keys[i] != null) { temp.put(keys[i], vals[i]); } } keys = temp.keys; vals = temp.vals; m = temp.m;}
参考文献:
[1] 数据结构(C语言版)
[2] 算法(第4版)
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 哈希表总结
- 关于哈希表的总结
- 转自: 哈希表总结
- 哈希表的问题总结
- 哈希表学习总结
- 哈希表 (自我总结
- 排序与哈希表总结
- 总结
- Android Studio如何显示行数
- Android WindowManager对于窗口的管理以及悬浮窗的实现
- xcode9无线调试都在这里
- HDU1091
- 图片文件上传(blob)
- 哈希表总结
- android ZXing扫描 返回崩溃问题,图像拉伸
- SpringMVC控制器controller单例问题
- C语言字符串常用函数
- Ubuntu 15.10快速搭建本地源服务器
- 容器的排序-1
- 表单文字个数不同左右对齐方式
- Redis实现分布式session功能的共享
- 侧滑栏&动态添加轮播图下的按钮&shape绘制按钮