哈希表实现指南:从原理到C++实践

贾蔷
• 阅读 2

一、简介和应用 哈希表(Hash Table)是一种高效的数据结构,通过键值对(key-value)存储数据,提供快速的插入、删除和查找操作。它使用哈希函数将键映射到表中的位置,使得平均时间复杂度可以达到O(1)。

‌应用场景‌:数据库索引、缓存实现(如Redis)、字典和符号表、编译器中的变量管理、网络路由表、密码存储和验证。

二、特点和注意事项 ‌特点‌:

1.快速访问:平均时间复杂度O(1) 2.灵活大小:可以动态调整容量 3.冲突处理:使用链表法解决哈希冲突 4.简单接口:提供插入、删除、查找基本操作 5.内存效率:相比其他数据结构更节省空间 三、实现步骤解析 ‌定义键值对结构‌:创建存储键值对的pairs结构 ‌实现链表节点‌:模板化的链表节点用于处理冲突 ‌哈希表类设计‌: 初始化哈希表数组 提供默认和指定大小的构造函数 ‌核心操作实现‌: 插入:计算哈希地址,处理冲突 删除:查找并移除指定键 查找:快速定位键对应的值 ‌辅助功能‌: 打印整个哈希表内容 四、完整代码和注释

#include<iostream>using namespACe std;// 键值对结构体struct pairs {
    int key;  // 键
    int val;  // 值};// 链表节点模板template<typename T>struct listnode {
    T val;            // 存储的值
    listnode* next=nullptr; // 下一个节点指针

    // 默认构造函数
    listnode() {}

    // 带值构造函数
    listnode(T v) {
        val = v;
    }};// 哈希表类class hash_map {
    listnode<pairs>** map; // 哈希表数组(链表指针数组)
    int size;              // 哈希表大小
    public:
    // 默认构造函数(大小1000)
    hash_map() {
        size = 1000;
        map = new listnode<pairs>*[size]; // 分配数组
        for (int i = 0; i < size; i++) {
            map[i] = nullptr; // 初始化每个槽位为空
        }
    }

    // 指定大小的构造函数
    hash_map(int size) {
        this->size = size;
        map = new listnode<pairs>*[size];
        for (int i = 0; i < size; i++) {
            map[i] = nullptr;
        }
    }

    // 插入键值对
    void ins(pairs pair) {
        int address = pair.key % size; // 计算哈希地址
        listnode<pairs>* newnode = new listnode<pairs>(pair); // 创建新节点

        listnode<pairs>* tmp = map[address]; // 获取槽位头节点

        // 如果槽位为空,直接插入
        if (!tmp) {
            map[address] = newnode;
            return;
        }

        // 否则找到链表末尾插入
        while (tmp->next) {
            tmp = tmp->next;
        }
        tmp->next = newnode;
    }

    // 删除指定键的节点
    void del(int key) {
        int address = key % size; // 计算哈希地址
        listnode<pairs>* tmp = map[address]; // 获取槽位头节点

        // 如果头节点就是要删除的节点
        if (tmp->val.key == key) {
            map[address] = map[address]->next; // 跳过该节点
            return;
        }

        // 否则遍历查找要删除的节点
        while (tmp->next->val.key != key) {
            tmp = tmp->next;
        }
        tmp->next = tmp->next->next; // 跳过要删除的节点
    }

    // 查找指定键的值
    int find(int key) {
        int address = key % size; // 计算哈希地址
        listnode<pairs>* tmp = map[address]; // 获取槽位头节点

        // 遍历链表查找键
        while (tmp and tmp->val.key != key) {
            tmp = tmp->next;
        }

        // 如果没找到返回-1
        if (!tmp) return -1;

        // 找到返回对应的值
        return tmp->val.val;
    }

    // 打印整个哈希表
    void print() {
        for (int i = 0; i < size; i++) {
            listnode<pairs>* tmp = map[i]; // 获取每个槽位的头节点

            // 打印该槽位的所有键值对
            while (tmp) {
                cout << tmp->val.key << ":" << tmp->val.val << " ";
                tmp = tmp->next;
            }
            cout << endl;
        }
        cout << endl;
    }};

五、总结 哈希表是一种极其重要的数据结构,本文通过C++实现展示了其基本原理和核心操作。理解哈希表的工作原理对于学习更高级的数据结构和算法至关重要。在实际应用中,可以根据需求调整哈希函数、冲突解决策略和扩容机制来优化性能。 链接:哈希表

点赞
收藏
评论区
推荐文章
HashMap的理解
HashMap在Map.Entry静态内部类实现中存储keyvalue对。HashMap使用哈希算法,在put和get方法中,它使用hashCode()和equals()方法。当我们通过传递keyvalue对调用put方法的时候,HashMap使用KeyhashCode()和哈希算法来找出存储keyvalue对的索引。Entry存储在LinkedL
Wesley13 Wesley13
3年前
15.链地址法
同样是为了解决哈希表中索引重复问题的算法,基本思路为将哈希表中维护的数组改成存储链表的数组,将数据存在链表中。也可以用数组但是数组的插入和删除的效率较低,故采用链表。实现:链表的实现:/链结点,相当于是车厢/publicclassNode{//数据域publi
Wesley13 Wesley13
3年前
MySql数据库索引
InnoDB存储引擎索引:B树索引:不能找到一个给定键值的具体行,能找到的只是被查找数据行所在的页。然后把页加载到内存,在查询所要的数据。全文索引:哈希索引:InnoDB会根据表的使用情况自动为表生成哈希索引,不能人为的干预是否在一张表中生成哈希索引B树索引在数据库中的高度一般是2~4层,所以查询最多需要2到4次IO。B树索引分为聚
Stella981 Stella981
3年前
Redis基础与性能调优
Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库、缓存服务或消息服务使用。Redis支持多种数据结构,包括字符串、哈希表、链表、集合、有序集合、位图、Hyperloglogs等。Redis具备LRU淘汰、事务实现、以及不同级别的硬盘持久化等能力,并且支持副本集和通过RedisSentinel实现的高可用方案,
Stella981 Stella981
3年前
List、Map、Set三个接口存取元素时,各有什么特点
List接口以特定索引来存取元素,可以有重复元素Set接口不可以存放重复元素(使用equals方法区分是否重复)Map接口保存的是键值对(keyvaluepair)映射,映射关系可以是一对一或者多对一(key唯一)Set和Map容器都有基于哈希存储和排序树的两种实现版本。基于哈希存储的版本的实现理论存取时间复杂度是O(1),而基于排序树版本的
Wesley13 Wesley13
3年前
Java集合之Map接口
Map使用键值对来存储数据,将键映射到值对象,一个映射不能包含重复的键,每一个键最多只能映射到一个值。Map接口的具体实现类:HashMap,Hashtable,TreeMap,LinkedHashMap  1)HashMap  基于哈希表(哈希表学习地址)的Map接口实现。允许使用null值和null键,不保证映射的顺序,特别是不保证顺序恒
Stella981 Stella981
3年前
Redis哈希对象的ziplist编码实现了O(1)复杂度吗
问题:Redis中哈希对象有两种编码方式,分别是ziplist、hashtable方式。哈希对象,总得体现哈希算法,使得基本操作达到O(1)的效率。hashtable编码方式使用字典,也即是Java中hashMap的方式,这个我可以理解。但是,ziplist方式所有元素都是紧挨的,它是怎么实现hash,并使得查询等操作有O(1)的时间效率的呢?让我们
Stella981 Stella981
3年前
Redis面试:八问字典内部构造与rehash,这谁顶的住啊!
字典是一种用于保存键值对的抽象数据结构,也被称为查找表、映射或关联表。在字典中,一个键(key)可以和一个值(value)进行关联,这些关联的键和值就称之为键值对。抽象数据结构,啥意思?就是可以需要实际的数据结构是实现这个功能。抽象,意味着它这是实现功能的标准,凡是能够完成这些功能的都可以是其实现。redis的字典
Wesley13 Wesley13
3年前
MySQL索引初探
一、什么是索引?帮助数据库系统实现高效获取数据的数据结构索引可以帮助我们快速地定位到数据而不需要每次搜索的时候都遍历数据库中的每一行。二、常见实现方式有哪些?常见索引模型有三种:哈希表、有序数组、搜索树1.哈希表(1)使用哈希表实现的索引称为哈希索引。!(https://os
小万哥 小万哥
1年前
Java HashMap 和 HashSet 的高效使用技巧
JavaHashMapHashMap是一种哈希表,它存储键值对。键用于查找值,就像数组中的索引一样。HashMap的优势在于它可以使用任何类型作为键,并且查找速度很快。创建HashMapjava//导入HashMap类importjava.util.Has