哈希表总结

1.哈希表和哈希地址定义

解析:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映像到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为哈希表,这一映像过程称为哈希造表或散列,所得存储位置称哈希地址或散列地址。

 

2.哈希函数构造方法

解析:

[1]直接定址法

[2]数字分析法

[3]平方取中法:取关键字平方后的中间几位为哈希地址。这是一种较常用的构造哈希函数的方法。通常在选定哈希函数时不一定能知道关键字的全部情况,取其中哪几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定。

[4]折叠法:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。在折叠法中数位叠加可以有移位叠加和间界叠加两种方法。移位叠加是将分割后的每一部分的最低位对齐,然后相加;间界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。关键字位数很多,而且关键字中每一位上数字分布大致均匀时,可以采用折叠法得到哈希地址。

[5]除留余数法

[6]随机数法:选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较恰当。

说明:构造哈希函数需要考虑的因素:计算哈希函数所需时间[包括硬件指令的因素];关键字的长度;哈希表的大小;关键字的分布情况;记录的查找频率。

 

3.处理哈希地址冲突方法

解析:

[1]开放定址法

[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版]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NLP工程化

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值