当前位置: 首页 > news >正文

数据结构 -- 哈希表

哈希表(Hash Table)核心概念

  • 定义:一种支持高效存储与查找的数据结构,目标查找复杂度为 O(1)∼O(lgN) ,通过哈希函数映射数据到存储位置,平衡存储与查询效率。

  • 核心要素

    1. 哈希函数(Hash Fun)
      • 作用:将输入的 key(要存储的数据)转换为哈希表的下标,确定数据存储位置。
      • 要求:计算快捷(降低时间开销)、地址分布均匀(减少冲突概率)。
      • 示例(数字场景):常用求余运算(如 key % 哈希表长度 )。
    2. 哈希表(Hash Table):存储数据的连续空间,通过哈希函数映射的下标访问,是哈希逻辑的载体。
  • 冲突(Collision):不同 key 经哈希函数计算得到相同下标(即 fun(key1) == fun(key2) ),需通过探测策略解决。常见探测方式:

    探测策略描述示例探测序列(假设基础下标为 i
    线性探测按顺序遍历后续下标i+1, i+2, i+3, ...(或循环回表首)
    二次探测按 “平方级偏移” 遍历下标i+1, i-1, i+2, i-2, ...(避免连续扎堆)
    随机探测用随机数生成偏移量i + rand()(依赖随机算法,分布更灵活)

关键逻辑梳理

  1. 存储流程
    数据 → 哈希函数计算下标 → 若下标位置空闲,直接存储;若冲突,按探测策略找新位置存储。
  2. 查找流程
    目标 key → 哈希函数计算下标 → 比对数据,若匹配则命中;若不匹配,按探测策略遍历查找(或判定不存在)。
  3. 设计权衡
    • 哈希函数越简单、分布越均匀,存储 / 查询效率越高,但冲突仍难完全避免。
    • 探测策略影响冲突解决效率:线性探测实现简单但易引发 “聚集”;二次 / 随机探测可分散冲突,却增加实现复杂度。

实现函数

#include <stdio.h>   // 标准输入输出库,用于printf等函数
#include <stdlib.h>  // 标准库,用于malloc、free等内存管理函数
#include <string.h>  // 字符串处理库,用于memcpy等内存拷贝函数// 定义哈希表存储的数据类型为int
typedef int DATATYPE;// 哈希表结构体定义
typedef struct
{DATATYPE* head;  // 指向哈希表数组的首地址int tlen;        // 哈希表的长度(数组大小)
} HS_Table;/*** @brief 创建哈希表* * @param len 哈希表的长度* @return HS_Table* 成功返回哈希表指针,失败返回NULL*/
HS_Table* CreateHsTable(int len)
{// 为哈希表结构体分配内存HS_Table* hs = malloc(sizeof(HS_Table));if (NULL == hs)  // 内存分配失败检查{perror("CreateHsTable malloc1");  // 打印错误信息return NULL;}// 为哈希表数组分配内存hs->head = malloc(sizeof(DATATYPE) * len);if (NULL == hs->head)  // 内存分配失败检查{perror("CreateHsTable malloc2");  // 打印错误信息free(hs);  // 释放已分配的结构体内存,防止内存泄漏return NULL;}hs->tlen = len;  // 设置哈希表长度// 初始化哈希表,将所有元素设为-1(表示该位置为空)int i = 0;for (i = 0; i < len; i++){hs->head[i] = -1;}return hs;  // 返回创建好的哈希表
}/*** @brief 哈希函数:根据需要存储的数据计算下标*  设计原则:1.计算过程尽可能简单 2.使下标均匀分布* * @param h 哈希表指针* @param data 需要计算下标的数据* @return int 计算得到的下标*/
int HS_Fun(HS_Table* h, DATATYPE* data)
{// 使用取模运算作为哈希函数,data对哈希表长度取模return *data % h->tlen;
}/*** @brief 向哈希表中插入数据* * @param h 哈希表指针* @param data 要插入的数据* @return int 0表示成功*/
int HS_Insert(HS_Table* h, DATATYPE* data)
{// 计算数据应插入的初始位置int ind = HS_Fun(h, data);// 处理哈希冲突:当计算的位置已有数据时,使用线性探测法寻找下一个空位置// 线性探测法:如果当前位置被占用,则检查下一个位置,直到找到空位置while (-1 != h->head[ind])  // -1表示位置为空{printf("data:%d ind:%d 发生冲突\n", *data, ind);  // 打印冲突信息ind = (ind + 1) % h->tlen;  // 计算下一个位置,循环到表的开始}// 将数据插入到找到的空位置memcpy(&h->head[ind], data, sizeof(DATATYPE));return 0;  // 插入成功
}/*** @brief 在哈希表中查找数据* * @param h 哈希表指针* @param data 要查找的数据* @return int 找到返回数据所在下标,未找到返回-1*/
int HS_Search(HS_Table* h, DATATYPE* data)
{// 计算数据可能存在的初始位置int ind = HS_Fun(h, data);int old_ind = ind;  // 保存初始位置,用于判断是否遍历完整个表//由于哈希表是 “循环数组”(通过% h->tlen实现循环),需要一个 “起点标记” 来判断是否已经遍历了整个哈希表。old_ind就是这个起点,当后续查找绕回old_ind时,说明所有位置都已检查过// 查找数据,处理可能的哈希冲突while (*data != h->head[ind])    //// 若当前位置不是目标数据,继续查找{ind = (ind + 1) % h->tlen;  // 检查下一个位置// 如果回到初始位置,说明整个表已遍历完毕且未找到数据if (ind == old_ind){return -1;  // 未找到}}return ind;  // 找到数据,返回下标
}// 哈希表销毁函数声明(未实现)
int HS_Destroy(HS_Table* h);/*** @brief 主函数:演示哈希表的创建、插入和查找操作*/
int main(int argc, char** argv)
{// 创建长度为12的哈希表HS_Table* hs = CreateHsTable(12);// 准备要插入的数据int array[12] = {12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34};// 将数据插入哈希表int i = 0;for (i = 0; i < 12; i++){HS_Insert(hs, &array[i]);}// 在哈希表中查找数据12int want_num = 12;int ret = HS_Search(hs, &want_num);if (-1 == ret){printf("未找到 %d\n", want_num);}else{printf("找到 %d,位于下标 %d\n", want_num, ret);}// 注意:此处缺少哈希表的销毁操作,实际应用中应调用HS_Destroy释放内存return 0;
}

http://www.dtcms.com/a/347631.html

相关文章:

  • RAGFlow (一) 开发环境搭建
  • imx6ull-驱动开发篇37——Linux MISC 驱动实验
  • [机械结构设计-18]:Solidworks - 特征(Feature)是构成三维模型的基本单元,是设计意图的载体,也是参数化设计的核心。
  • 深入剖析分布式事务的Java实现:从理论到Seata实战
  • c语言中enum与#define的用法区别
  • 算法题(189):食物链
  • 如何利用数据库事务,来防止数据不一致的问题
  • 云原生概述
  • [e3nn] 归一化 | BatchNorm normalize2mom
  • 自然语言处理——06 迁移学习(上)
  • MATLAB实现CNN-LSTM-Attention 时序和空间特征结合-融合注意力机制混合神经网络模型的风速预测
  • 云计算-K8s 运维:Python SDK 操作 Job/Deployment/Pod+RBAC 权限配置及自定义 Pod 调度器实战
  • Kubernetes相关问题集(四)
  • 「数据获取」《贵港统计年鉴》(2008-2023)(2016、2017缺失)(获取方式看绑定的资源)
  • 开发指南134-路由传递参数
  • 【KO】前端面试七
  • 科研笔记:博士生手册
  • n8n热门的开源 AI 工作流平台实操
  • git实战(7)git常用命令速查表
  • C++实现常见的排序算法
  • STM32窗口看门狗(WWDG)深度解析:精准守护嵌入式系统的实时性
  • day39-keepalived
  • How to Use Managed Identity with ACS?
  • 全面解析主流AI模型:功能对比与应用推荐
  • douyin_search_tool:用python开发的抖音关键词搜索采集软件
  • 低功耗全双工远距离无线对讲解决方案
  • 【数位DP】D. From 1 to Infinity
  • 数据库字段类型深度解析:从关系型到 NoSQL 的全面指南
  • Placement new是什么
  • CUDA和torch的安装