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

【数据结构与算法】哈希表

哈希表

  • 一.哈希表的原理
  • 二.哈希链表数据结构
  • 三.哈希链表的算法实现
    • 1.哈希函数
    • 2.哈希链表初始化
    • 3.哈希链表查找元素
    • 4.哈希链表插入元素
    • 5.哈希链表删除元素
    • 6.哈希链表获取数据
    • 7.哈希链表的销毁
    • 8.图释
  • 四.完整代码
    • 1.头文件
    • 2..c文件
    • 3.运行结果

一.哈希表的原理

假设我们有24位成员,我们要进行分组,那么我们可以这样分:
首先对24位成员进行1~24的编号.
假如我们要分6组,那么我们用成员自己的编号 %6余数相同的分为一组.
在这里插入图片描述
那么我们就可以很快的得到如上的分组.
为什么要如此分?答案是我们可以很快的找到我们要的人,你只需要 %6就可以很快的知道在哪一组,可以一下子排除5组,比二分法还牛逼.
所以其查找效率是非常惊人的.

像这张表我们就可以称其为哈希表,又称为散列.
我们来看哈希表的几个重要的组成成分,编号我们称之为关键码(key),对关键码取模这是一种散列函数,当然不止取模.取模是最常见的.

二.哈希链表数据结构

哈希表的实现既可以用链式结构也可以用顺序结构.
这里我们采用链式结构.
哈希表的重点在于分组,那么我们就可以用余数来作为组数.
在这里插入图片描述
可以将其作为一个头节点存放在一个数组中,方便我们索引.
在这里插入图片描述
ListNode是节点,其中包含关键码,数据,和指向下一个节点的指针.
HashTable就是我们刚刚画的那个头结点数组,因为动态分配内存.
Thelists我们用的二级指针,里面放的是节点指针.
tableSize就是有多少组.

三.哈希链表的算法实现

1.哈希函数

就是为了将我们的关键码转换到对应的组中.
在这里插入图片描述

2.哈希链表初始化

对于哈希表的初始化,我们要传入一个组数.
如果组数为负,我们就用默认的宏.
对哈希表动态分配内存,不成功就直接返回.
在这里插入图片描述
接下来就对头结点数组动态分配内存.
注意这里就是分配的数组了哦,*TableSize
在这里插入图片描述
然后对数组内的节点动态分配内存.
分配完后,我们将数据都设置为空,就是作为该组头节点.
在这里插入图片描述
现在就相当于这样:
在这里插入图片描述

3.哈希链表查找元素

我们要查找一个元素,那么我们先要知道其组号.
用哈希函数就可以知道.
然后在组中比对即可.
因为组的第一个是头节点,我们从第二个进行对比.
找到之后,返回节点.
在这里插入图片描述

4.哈希链表插入元素

首先我们需要先进行查找,因为我们的编号是具有唯一性的.
如果已经存在就不能进行插入.
如果不存在,我们就动态分配一个节点,对其赋值,然后插入其中.
我们还是要用哈希函数来确定我们擦入那个组.
这里我们用的前插法.
在这里插入图片描述

5.哈希链表删除元素

先找到要删除位置的组,然后进行删除.
用last来指向要删除节点的上一个节点,这样就可以直接删除了.
如果为空说明没找到.
在这里插入图片描述

6.哈希链表获取数据

因为我们查找是得到的节点,所以我们用这个来获取节点的数据.
注意数据类型转换,因为我们数据用的void*
在这里插入图片描述

7.哈希链表的销毁

有动态分配内存的地方,我们就要释放,我们要对节点释放,对头结点释放,对头结点数组释放,对哈希表释放.
在这里插入图片描述

8.图释

在这里插入图片描述
就像这样.

四.完整代码

1.头文件

#pragma once
#define DEFAULT_SIZE 16typedef struct _ListNode
{int key;struct _ListNode* next;void* data;
}ListNode;typedef ListNode* List;
typedef ListNode* Element;typedef struct _HashTable
{int tableSize;List* Thelists;
}HashTable;int Hash(int key, int TableSize);HashTable* initHash(int tableSize);void insert(HashTable* HashTable, int key, void* value);Element Find(HashTable* HashTable, int key);void Destory(HashTable* HashTable);void* Retrieve(Element e);

2…c文件

#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include"hash_table.h"int Hash(int key, int TableSize)
{return key % TableSize;
}HashTable* initHash(int TableSize)
{HashTable* hTable = NULL;if (TableSize <= 0){TableSize = DEFAULT_SIZE;}hTable = (HashTable*)malloc(sizeof(HashTable));if (hTable == NULL){printf("HashTable malloc error.\n");return NULL;}hTable->tableSize = TableSize;hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);if (hTable->Thelists == NULL){printf("HashTable malloc error.\n");free(hTable);return NULL;}for (int i = 0; i < TableSize; i++){hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));if (hTable->Thelists[i] == NULL){printf("HashTable malloc error.\n");free(hTable->Thelists);free(hTable);return NULL;}else{memset(hTable->Thelists[i], 0, sizeof(ListNode));}}return hTable;
}Element Find(HashTable* HashTable, int key)
{int i = 0;List L = NULL;Element e = NULL;i = Hash(key, HashTable->tableSize);//得到下标L = HashTable->Thelists[i];//得到组的头节点e = L->next;//从第一个真正的元素开始.while (e!=NULL&&e->key!=key){e = e->next;}return e;
}void insert(HashTable* HashTable, int key, void* value)
{Element e = NULL, tmp = NULL;List L = NULL;e = Find(HashTable, key);if (e==NULL){tmp = (Element)malloc(sizeof(ListNode));if (tmp == NULL){printf("malloc error\n");return;}int i = Hash(key, HashTable->tableSize);L = HashTable->Thelists[i];tmp->data = value;tmp->key = key;tmp->next = L->next;//前插法L->next = tmp;}else{printf("the key already exist\n");}
}void Delete(HashTable* HashTable, int key)
{Element e = NULL, last = NULL;List L = NULL;int i= Hash(key, HashTable->tableSize);L = HashTable->Thelists[i];last = L;e = L->next;while (e!=NULL&&e->key!=key){last = e;e = e->next;}if (e){last->next = e->next;free(e);}
}void* Retrieve(Element e)
{return e ? e->data : NULL;
}void Destory(HashTable* HashTable)
{int i = 0;List L = NULL;Element cur = NULL, next = NULL;for (i = 0; i < HashTable->tableSize; i++){L = HashTable->Thelists[i];cur = L->next;while (cur!=NULL){next = cur->next;free(cur);cur = next;}free(L);}free(HashTable->Thelists);free(HashTable);
}int main(void)
{char* elems[] = { "姚哥","小美","大美" };int i = 0;HashTable* HashTable;HashTable = initHash(31);insert(HashTable, 1, elems[0]);insert(HashTable, 2, elems[1]);insert(HashTable, 3, elems[2]);Delete(HashTable, 1);for (int i = 0; i < 4; i++){Element e = Find(HashTable, i);if (e){printf("%s\n", (const char* )Retrieve(e));}else{printf("not found [key:%d]\n", i);}}system("pause");return 0;
}

3.运行结果

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • JAVA—异常
  • 深度学习入门指南(1) - 从chatgpt入手
  • Docker③_VMware虚拟机和Docker的备份与恢复
  • CST软件如何设置硬件加速选项GPU DCMPI token?
  • (自用)交互协议设计——protobuf序列化
  • python笔记和练习----少儿编程课程【阶段一(二)】
  • 【案例38】Can’t get connection from database 排查详细记录
  • GPS跟踪环路MATLAB之——数字锁频环
  • 可视耳勺靠谱吗?五款杰出可视挖耳勺种草!
  • Windows 平台 Docker Protainer可视化平台,忘记登录密码,重置密码
  • 【C++算法】双指针
  • 45.跳跃游戏
  • 爬虫练习_01
  • 代码随想录算法day16 | 二叉树part06 | 654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树
  • 做报表用什么工具?不想再用Excel了!!!
  • 【347天】每日项目总结系列085(2018.01.18)
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • angular组件开发
  • bootstrap创建登录注册页面
  • java小心机(3)| 浅析finalize()
  • leetcode-27. Remove Element
  • Python十分钟制作属于你自己的个性logo
  • React+TypeScript入门
  • Swoft 源码剖析 - 代码自动更新机制
  • Vue--数据传输
  • webgl (原生)基础入门指南【一】
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 前端面试之CSS3新特性
  • 前端之Sass/Scss实战笔记
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 实现简单的正则表达式引擎
  • 听说你叫Java(二)–Servlet请求
  • 小程序测试方案初探
  • 终端用户监控:真实用户监控还是模拟监控?
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • # 透过事物看本质的能力怎么培养?
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #QT(智能家居界面-界面切换)
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (初研) Sentence-embedding fine-tune notebook
  • (二)windows配置JDK环境
  • (分布式缓存)Redis分片集群
  • (规划)24届春招和25届暑假实习路线准备规划
  • (十)Flink Table API 和 SQL 基本概念
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • .apk文件,IIS不支持下载解决
  • .NET gRPC 和RESTful简单对比
  • .Net 高效开发之不可错过的实用工具
  • .Net 基于.Net8开发的一个Asp.Net Core Webapi小型易用框架
  • .NET 指南:抽象化实现的基类
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .net通过类组装数据转换为json并且传递给对方接口
  • .NET序列化 serializable,反序列化