【高级程序设计语言C++】哈希桶

news2024/11/25 2:44:10

  • 1. 哈希桶概念
  • 2. 哈希桶的基础模型
  • 3. 哈希桶的插入
  • 4. 哈希桶的删除
  • 5. 哈希桶的查找

1. 哈希桶概念

在C++中,哈希桶是一种用于实现哈希表的数据结构。哈希表是一种高效的数据结构,用于存储键值对,并支持快速的插入、查找和删除操作。

哈希桶的基本思想是通过将键映射到桶中的索引来存储和访问数据。具体实现中,通常使用一个数组来表示桶,每个桶可以存储一个或多个键值对。为了将键映射到桶中的索引,通常使用哈希函数来计算键的哈希值,然后对桶的数量取模,得到键的索引。

哈希桶可以理解为一个指针数组,数组的每个元素都是一个指针,而这个指针是一个单链表的表头,数组的每一个位置都挂着一个单链表。

如图所示:

img

这一个个的单链表你可以把他当成桶来看。哈希桶又名链地址法,因此元素是一个个的单链表。

2. 哈希桶的基础模型

class HashBucket
	{
		typedef HashBucketNode<V> Node;
		typedef Node* PNode;
	public:
		HashBucket(size_t capacity)
			: _table(GetNextPrime(capacity))
			, _size(0)
		{}
		~HashBucket()
		{
			Clear();
		}
	private:
		vector<Node*> _table;
		size_t _size;      // 哈希表中有效元素的个数
	};

3. 哈希桶的插入

哈希桶的插入有以下步骤

  1. 先用哈希函数找到要插入的位置
  2. 再用头插法插入到单链表中

注意:

  1. 这里的插入都是不插入重复元素
  2. 注意扩容的问题

代码如下:

Node* Insert(const V& data)
{
    // 0. 检测是否需要扩容
    CheckCapacity();

    // 1. 通过哈希函数计算data所在的桶号
    size_t bucketNo = HashFunc(data);

    // 2. 检测该元素是否在bucketNo桶中
    //    本质:检测链表中是否存在data的节点
    Node* pCur = _table[bucketNo];
    while (pCur)
    {
        if (pCur->_data == data)
            return nullptr;

        pCur = pCur->_pNext;
    }

    // 插入新节点
    pCur = new Node(data);
    pCur->_pNext = _table[bucketNo];
    _table[bucketNo] = pCur;
    ++_size;
    return pCur;
}

扩容的代码:

void CheckCapacity()
{
    if (_size == _table.capacity())
    {
        // 将旧哈希桶中的节点直接向新哈希桶中搬移
        for (size_t i = 0; i < _table.capacity(); ++i)
        {
            Node* pCur = _table[i];
            while (pCur)
            {
                // 将pCur节点从旧哈希桶搬移到新哈希桶
                // 1. 将pCur节点从旧链表中删除
                _table[i] = pCur->_pNext;

                // 2. 将pCur节点插入到新链表中
                size_t bucketNo = ht.HashFunc(pCur->_data);

                // 3. 插入节点--->头插
                pCur->_pNext = ht._table[bucketNo];
                ht._table[bucketNo] = pCur;
            }
        }
        this->Swap(ht);
    }
}

4. 哈希桶的删除

删除有以下步骤

  1. 先用哈希函数找到删除元素的位置
  2. 从该位置的头节点开始,遍历链表
  3. 找到元素,开始删除,变换节点

代码如下:

bool Erase(const V& data)
{
    size_t bucketNo = HashFunc(data);
    Node* pCur = _table[bucketNo];
    Node* pPre = nullptr;

    while (pCur)
    {
        if (data == pCur->_data)
        {
            // 删除
            if (_table[bucketNo] == pCur)
            {
                // 删除第一个节点
                _table[bucketNo] = pCur->_pNext;
            }
            else
            {
                // 删除的不是第一个节点
                pPre->_pNext = pCur->_pNext;
            }

            delete pCur;
            --_size;
            return true;
        }

        pPre = pCur;
        pCur = pCur->_pNext;
    }

    return false;
}

5. 哈希桶的查找

查找的步骤如下:

  1. 先用哈希函数确定元素的位置
  2. 遍历该位置的链表,找到元素
Node* Find(const V& data)
{
    size_t bucketNo = HashFunc(data);
    Node* pCur = _table[bucketNo];
    while (pCur)
    {
        if (data == pCur->_data)
            return pCur;

        pCur = pCur->_pNext;
    }
    return nullptr;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/878519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM02汇编指令

文章目录 一、keil软件介绍1.1 创建工程1.2 解析start.s文件(重点)1.3 乱码解决1.4 更换背景颜色1.5 C语言内存分布1.6 解析map.lds文件(重点)1.7 常见错误信息1.8 仿真 二、汇编三种符号2.1 汇编指令2.2 伪指令2.3 伪操作 三、汇编指令格式3.1 格式3.2 注意事项 四、数据操作指…

如何看懂统一社会信用代码?

在查看企业信息的时候&#xff0c;我们通常第一时间查看的就是该企业的照面信息&#xff1a;企业名称&#xff0c;企业信用代码&#xff0c;企业法人等等。 其中统一社会信用代码就是给各个企业组织编号&#xff0c;是便于统一识别管理的一串代码&#xff0c;类似我们的身份证…

【Spring专题】Spring之Bean的生命周期源码解析——阶段二(IOC之实例化)

目录 前言阅读准备阅读指引阅读建议 课程内容一、SpringIOC之实例化1.1 简单回顾1.2 概念回顾1.3 核心方法讲解 二、方法讲解2.1 AbstractBeanFactory#getMergedLocalBeanDefinition&#xff1a;合并BeanDefinition2.2 AbstractAutowireCapableBeanFactory#createBean&#xff…

k8s ------存储卷(PV、PVC)

目录 一&#xff1a;为什么需要存储卷&#xff1f; 二&#xff1a;emptyDir存储卷 ​三&#xff1a;hostPath存储卷 四&#xff1a;nfs共享存储卷 五&#xff1a;PVC 和 PV 1、PVC 和 PV介绍 2、PV和PVC之间的相互作用遵循的生命周期 3、PV 的4 种状态 4、一个PV从创…

redis的三种集群方式

redis有三种集群方式&#xff1a;主从复制&#xff0c;哨兵模式和集群。 1.主从复制 主从复制原理&#xff1a; 从服务器连接主服务器&#xff0c;发送SYNC命令&#xff1b; 主服务器接收到SYNC命名后&#xff0c;开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所…

netty学习分享 二

操作系统IO模型与实现原理 阻塞IO 模型 应用程序调用一个IO函数&#xff0c;导致应用程序阻塞&#xff0c;等待数据准备好。如果数据没有准备好&#xff0c;一直等待….数据准备好了&#xff0c;从内核拷贝到用户空间,IO函数返回成功指示。 当调用recv()函数时&#xff0c;系…

mysql使用redis+canal实现缓存一致性

一、开启binlog日志 1.首先查看是否开启了binlog show variables like %log_bin%; 如果是OFF说明位开启 2、开启binlog日志&#xff0c;并重启mysql服务 右键我的电脑——管理——服务——MYSQL——属性 这里是my.ini地址 在[mysqld]底下添加 log-bin mysqlbinlog binlog-f…

Revit SDK: MaterialQuantities

前言 这个例子介绍了如何分类统计材质的和面积。用到的接口是 Element 的&#xff1a; // 返回 Element 中用到的材质 ICollection<ElementId> GetMaterialIds(bool returnPaintMaterials); // Element 获取某材质的体积 double GetMaterialVolume(ElementId materialI…

【JavaWeb】MySQL约束、事务、多表查询

1 约束 PRIMARY KEY 主键约束 UNIQUE 唯一约束 NOT NULL 非空约束 DEFAULT 默认值约束 FOREIGN KEY 外键约束 主键 主键值必须唯一且非空&#xff1b;每个表必须有一个主键 建表时主键约束 CREATE TABLE 表名 (字段名 字段类型 PRIMARY KEY,字段名 字段类型 );CR…

利用SimpleDateFormat或者LocalDateTime生成格式为“yyyy-MM-dd HH:mm:ss“的当前时间

java程序&#xff1a; // 利用LocalDateTime生成格式为"yyyy-MM-dd HH:mm:ss"的当前时间 DateTimeFormatter formatter DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime now LocalDateTime.now(); String time1 now.format(format…

[C++] 模板template

目录 1、函数模板 1.1 函数模板概念 1.2 函数模板格式 1.3 函数模板的原理 1.4 函数模板的实例化 1.4.1 隐式实例化 1.4.2 显式实例化 1.5 模板参数的匹配原则 2、类模板 2.1 类模板的定义格式 2.2 类模板的实例化 讲模板之前呢&#xff0c;我们先来谈谈泛型编程&am…

不用技术代码,分班查询系统怎么做?

暑假即将结束&#xff0c;新学期开始将面临分班信息公布的工作&#xff01;对于分班信息公布&#xff0c;涉及到学生的个人信息&#xff0c;包括姓名、学号、班级等。在发布这些信息时&#xff0c;必须确保数据的保密性&#xff0c;防止未经授权的人员获取到学生的个人信息。因…

vite打包优化分片打包依赖包

在开发Vue3项目时&#xff0c;我们使用vite进行构建&#xff0c;由于项目中开发的是地图大屏项目&#xff0c;依赖较多&#xff0c;为了提高用户体验减少用户等待的时间&#xff0c;对此进行优化&#xff1a; 1.本文主要说的是拆分打包的方法&#xff1a; // vite.config.ts…

java Spring Boot yml多环境拆分文件管理优化

上文 java Spring Boot yml多环境配置 我们讲了多环境开发 但这种东西都放在一起 还是非常容易暴露信息的 并且对维护来讲 也不是非常的友好 这里 我们在resources下创建三个文件 分别叫 application-pro.yml application-dev.yml application-test.yml 我们直接将三个环境 转…

ARPC 是对ARQC 解密 然后返回一个处理结果?

第一次GAC是在输入密码之前还是之后&#xff1f;我理解是在输入密码之后&#xff0c;输入密码后就需要联机了&#xff1f; 可以说第一次GAC肯定在联机之前发生&#xff1f; 在 EMV 交易流程中&#xff0c;第一次 GAC&#xff08;Generational Application Cryptogram&#xf…

手把手教学优化docker镜像构建,使构建的镜像比官网的还小巧轻便 Dockerfile

为什么要docker减小镜像&#xff1f; 在使用docekrfile文件构建docker镜像时&#xff0c;即使时安装一个比较小的应用&#xff0c;构建后也是镜像&#xff0c;小到好几百M大到几个G&#xff0c; 这样非常不利与镜像之间的传输与上传到镜像仓库&#xff0c;部署的时候也会浪费时…

react入门到实战 学习笔记1 搭建

一、React是什么 一个专注于构建用户界面的 JavaScript 库&#xff0c;和vue和angular并称前端三大框架 React有什么特点 1- 声明式UI&#xff08;JSX&#xff09; 写UI就和写普通的HTML一样&#xff0c;抛弃命令式的繁琐实现 2- 组件化 组件是react中最重要的内容&#xf…

插槽Slot的作用和基本使用;具名插槽的使用;作用域插槽Slot使用;全局事件总线使用;依赖注入Provide/Inject

目录 1_插槽Slot的作用1.1_认识插槽Slot1.2_如何使用插槽slot1.3_插槽的默认内容1.4_多个插槽的效果 2_插槽Slot基本使用3_具名插槽的使用4_作用域插槽Slot使用4.1_渲染作用域4.2_认识作用域插槽4.3_独占默认插槽的缩写 5_全局事件总线使用5.1_全局事件总线mitt库5.2_使用事件总…

Java多线程编程中的线程间通信

Java多线程编程中的线程间通信 基本概念&#xff1a; ​ 线程间通信是多线程编程中的一个重要概念&#xff0c;指的是不同线程之间如何协调和交换信息&#xff0c;以达到共同完成任务的目的。 线程间通信的目的 ​ 是确保多个线程能够按照一定的顺序和规则进行协作&#xff…