散列表-拉链法(链地址法)完整代码实现

❤️️💚💙💛🧡💜🖤🤍🧡

大家好!我是曾续缘🥰

欢迎关注💕

❤️点赞 👍 收藏 ⭐再看,养成习惯

🔥人有两条路要走,一条是必须走的,一条是想走的,你必须把必须走的路走漂亮,才可以走想走的路。📚

散列表(也叫哈希表),是根据关键字值而直接进行访问的数据结构。

通过把关键字值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

在这里插入图片描述

散列函数的构造方法:

(1)直接定址法

(2)除留余数法

(3)平方取中法

(4)折叠法

(5)数值分析法

通常采用除留余法,通过对KEY进行求余,使得KEY分布在HashTable的数组中,同时为了减少键冲突,除数通常选择为素数。

本文介绍拉链法:将大小为 M 的数组中的每个元素指向一条链表,链表中的每个结点都存储了散列值为该元素的索引的键值对。

在这里插入图片描述

将关键码通过散列函数映射至特定的单链表中,当多个关键码映射至相同地址时,称这些关键码互为同义词,通过一个单链表存储同义词。

这个方法的基本思想就是选择足够大的 M ,使得所有链表都尽可能短以保证高效的查找。

1 拉链法解决冲突的方法

拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。

2 拉链法的优点

(1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;

(2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;

(3)当结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;

(4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。

结构体设计

template<class E, class K>
struct node {// 链表结点
    K key; // 键值
    E data; // 数据
    node<E, K>* next; // 下一个结点
    node() { next = nullptr; }
};
template<class E, class K>
class HashTable {
public:
    HashTable(int d);
    bool search(K key);// 查找
    bool insert(K key, E e); // 插入
    bool remove(K key); // 删除
    node<E, K>get(K key); // 获取值
    void print();
private:
    int divisor; // 散列方式为除留余数法
    int size, maxsize;
    node<E, K>** hash; // 指针数组
};

代码实现

template<class E, class K>
HashTable<E, K>::HashTable(int d) { // 初始化
    divisor = d;
    maxsize = d;
    size = 0;
    hash = new node<E, K>*[maxsize];
    if (hash == nullptr)exit(1);
    for (int i = 0;i < maxsize;i++)hash[i] = nullptr;
}
// 查找分两步:首先根据散列值找到对应的链表,然后沿着链表顺序查找对应的键。
template<class E, class K>
bool HashTable<E, K>::search(K key) {
    int i = key % divisor;
    node<E, K>* p = hash[i];
    while (p != nullptr && p->key != key)p = p->next;
    if (p == nullptr)return false;
    return true;
}
//  采用尾插法,从头到尾判断键值对是否已经存在,判断不存在后插入
template<class E, class K>
bool HashTable<E, K>::insert(K key, E e) {
    node<E, K>* p = nullptr, * s;
    int i = key % divisor;
    p = hash[i];
    s = new node<E, K>;
    s->key = key;
    s->data = e;
    if (p == nullptr) {
        hash[i] = s;
        size++;
        return true;
    }
    while (p != nullptr && p->key != key)p = p->next; //从头到尾判断键值对是否已经存在
    if (p != nullptr)return false;
    s->next = hash[i];
    hash[i] = s;
    size++;
    return true;
}

template<class E, class K>
bool HashTable<E, K>::remove(K key) {
    int i = key % divisor;
    node<E, K>* p = hash[i];
    if (p == nullptr)return false;
    if (p->key == key) {
        hash[i] = p->next;
        size--;
        delete p;
        p = nullptr;
        return true;
    }
    node<E, K>* cur = p->next;
    while (cur != nullptr && cur->key != key) {
        cur = cur->next;
        p = p->next;
    }
    if (cur == nullptr)return false;
    p->next = cur->next;
    size--;
    delete cur;
    return true;
}

template<class E, class K>
node<E, K> HashTable<E, K>::get(K key) {
    if (search(key)) {
        int i = key % divisor;
        node<E, K>* p = hash[i];
        while (p != nullptr && p->key != key)p = p->next;
        return *p;
    }
    return node<E, K>();
}

template<class E, class K>
void HashTable<E, K>::print() {
    for (int i = 0;i < maxsize;i++) {
        node<E, K>* p = hash[i];
        cout << i << ": ";
        while (p != nullptr) {
            cout << "(" << p->key << "," << p->data << ") ";
            p = p->next;
        }
        cout << endl;
    }
}

参考书籍推荐参考书籍

有用的话点个赞吧~关注@曾续缘,持续获取更多资料。

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值