数据结构小记【Python/C++版】——散列表篇
一,基础概念
散列表,英文名是hash table,又叫哈希表。
散列表通常使用顺序表来存储集合元素,集合元素以一种很分散的分布方式存储在顺序表中。
散列表是一个键值对(key-item)的组合,由键(key)和元素值(item)组成。键和它对应的元素值基于散列函数(hash function)进行一对一的映射,基于键查找到的元素值也可以称为散列值,查找公式:item = hash(key)。其中item可以是具体的值,也可以是具体的值对应的内存地址,也可以是链表或者链表的指针。
注意,有的教程里面喜欢把键值对称为(key, item),有的教程里面喜欢把键值对称为(index, value),其实是相同的意思。
散列表和数组相似的地方在于,都可以基于下标快速的访问数据,数组的下标是索引,散列表的下标是键。
散列表结构在生活中的抽象模型:一个班级所有学生的姓名和对应的学号。
二,散列表的图示结构
图一,key -> hash function -> hash table(key, item)
图二,哈希函数:item = key % 10
三,关于散列函数
最常见的散列函数:
除数留余法:item = (key + 5) % 10
例如:key=50, item = 5。key = 44, item = 9
好的散列函数具有以下特性:
函数的设计不过于复杂。
大部分情况下,使用相同的键只会查找到同一个值。
键和元素值要均匀随机分布。
基于键查找每个元素值的时间是近似的,而不是查找有的值耗时很长,查找有的值耗时很短。
发生散列冲突的概率极低。
四,散列冲突处理
所谓散列冲突,是指不同的键映射到了相同的散列值。
例如,对于”item = key % 10“的哈希函数,key为12或者22得到的散列值都是2。
方式一,链表法
在链表法中,散列表中的每个key都映射到一个链表。因此,当两个key具有相同的item值时,这两个key都被添加到相同的链表中。
方式二,线性探测法
线性探测法是开放寻址法中的一种,所谓开放寻址,是指如果出现了散列冲突,在散列表中重新找一块儿没被使用过的内存地址,组成新的键值对。
具体操作
基于当前key生成的item值,没有被其他键值对占用时。则该item值可以和key组成键值对来放进散列表中。如果该item值对应了已有的其他的key,则将该key映射到散列表中还没被使用的下一个位置的item值,组成新的键值对来放进散列表中。
对于当前场景,具体步骤为
step.01: 采用item=key%10的方式来获得哈希值。
step.02: 发现采用item= key%10的方式获得的哈希值被别的key占用了,于是采用item=(key+1)%10的方式来获得新的哈希值。
step.03: 发现采用item=(key+1)%10的方式获得的新哈希值没被占用,就将此哈希值作为key的item,生成键值对放入到散列表。否则,继续采用item=(key+2)%10的方式来获得哈希值,以此类推。
例如
根据key=70获得的哈希值也是0。但是那个位置已经被(key=10, item=0)占用了。因此,根据线性探测法,我们将继续找到下一个位置 1。由于该位置暂时未被占用,我们依此生成(key=70, item=1)的键值对。
两种方式对比
五,散列表常见操作
a.插入元素
step1.计算key对应的散列值。
step2.如果散列值不在散列表中,则插入生成新的键值对。
step3.如果散列值已经在散列表中,则发生了散列冲突,return返回或覆盖旧散列值或调用专门处理散列冲突的函数。
b.查找元素
step1.计算key对应的散列值。
step2.如果散列值在散列表中,则查找成功,否则,查找失败。
c.删除元素
对于链接法,执行和链表一样的删除操作。
对于开放寻址法,将被删除节点置为“已删除”标记,查找时跳过此节点,插入时重新覆盖该节点。
六,代码实现
1.Python实现:
class HashTable:def __init__(self, size):self.size = sizeself.hash_table = self.create_buckets()def create_buckets(self):#存储key用的桶结构return [[] for _ in range(self.size)]def insert_val(self, key, val):hashed_key = hash(key) % self.sizebucket = self.hash_table[hashed_key]found_key = Falsefor index, record in enumerate(bucket):record_key, record_val = recordif record_key == key:found_key = Truebreakif found_key:#遇到散列冲突时,直接覆盖了旧的值bucket[index] = (key, val)else:bucket.append((key, val))def get_val(self, key):hashed_key = hash(key) % self.sizebucket = self.hash_table[hashed_key]found_key = Falsefor index, record in enumerate(bucket):record_key, record_val = recordif record_key == key:found_key = Truebreakif found_key:return record_valelse:return "No record found"def delete_val(self, key):hashed_key = hash(key) % self.sizebucket = self.hash_table[hashed_key]found_key = Falsefor index, record in enumerate(bucket):record_key, record_val = recordif record_key == key:found_key = Truebreakif found_key:bucket.pop(index)return#魔法函数,遍历对象中的元素def __str__(self):return "".join(str(item) for item in self.hash_table)hash_table = HashTable(5)
hash_table.insert_val('key_1', 'value_1')
hash_table.insert_val('key_2', 'value_2')
hash_table.insert_val('key_3', 'value_3')
print(hash_table)print("the value of key_2 is: ", hash_table.get_val('key_2'))
hash_table.delete_val('key_3')
print(hash_table)
运行结果:
[][][('key_3', 'value_3')][('key_1', 'value_1'), ('key_2', 'value_2')][]
the value of key_2 is: value_2
[][][][('key_1', 'value_1'), ('key_2', 'value_2')][]
2.C++实现:
#include<iostream>
#include <list>
using namespace std;
class Hash
{int BUCKET;//每个散列值对应的链表list<int>* table;
public:Hash(int V); //插入元素void insertItem(int x);//删除元素void deleteItem(int key);//散列函数int hashFunction(int x) {return (x % BUCKET);}void displayHash();
};
Hash::Hash(int b)
{this->BUCKET = b;table = new list<int>[BUCKET];
}
void Hash::insertItem(int key)
{int value = hashFunction(key);table[value].push_back(key);
}
void Hash::deleteItem(int key)
{//找到key对应的散列值int index = hashFunction(key);list <int> ::iterator i;for (i = table[index].begin();i != table[index].end(); i++) {if (*i == key)break;}//删除key对应的元素if (i != table[index].end())table[index].erase(i);
}
void Hash::displayHash() {for (int i = 0; i < BUCKET; i++) {cout << i;for (auto x : table[i])cout << " --> " << x;cout << endl;}
}
int main()
{int a[] = { 15, 11, 27, 8, 12 };int n = sizeof(a) / sizeof(a[0]);Hash h(7); for (int i = 0; i < n; i++)h.insertItem(a[i]);h.deleteItem(12);h.displayHash();return 0;
}
运行结果:
0
1 --> 15 --> 8
2
3
4 --> 11
5
6 --> 27
3.内置数据类型实现
C++内置数据类型:STL标准库中的unordered_map容器
Python内置数据类型:Python字典dict
Demo1:
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{unordered_map<string, double> umap = {{"One", 1},{"Two", 2},{"Three", 3}};//insert valueumap["PI"] = 3.14;umap["root2"] = 1.414;umap.insert(make_pair("e", 2.718));string key = "PI";if (umap.find(key) == umap.end())cout << key << " not found\n\n";elsecout << "Found " << key << "\n\n";unordered_map<string, double>::iterator itr;cout << "\nAll Elements : \n";for (itr = umap.begin();itr != umap.end(); itr++){cout << itr->first << " " <<itr->second << endl;}
}
运行结果:
Found PIAll Elements :
One 1
Two 2
Three 3
PI 3.14
root2 1.414
e 2.718
Demo2:
dict_obj = {"a":1, "b":2, "c":3, "d":4}#打印字典
print(dict_obj['a'])#增加键值对
dict_obj['e'] = 5#修改字典的值
dict_obj['a'] = 21#删除键值对
del dict_obj['d']
print(dict_obj)#清空字典
dict_obj.clear()
print(dict_obj)
运行结果:
1
{'a': 21, 'b': 2, 'c': 3, 'e': 5}
{}
七,参考阅读
《Problem Solving with Algorithms and Data Structures Using Python, Second Edition》
https://www.softwaretestinghelp.com/hash-table-cpp-programs/
https://www.digitalocean.com/community/tutorials/hash-table-in-c-plus-plus
https://www.geeksforgeeks.org/hash-map-in-python/
https://scanftree.com/programs/cpp/c-program-for-hashing-with-chaining/
相关文章:

数据结构小记【Python/C++版】——散列表篇
一,基础概念 散列表,英文名是hash table,又叫哈希表。 散列表通常使用顺序表来存储集合元素,集合元素以一种很分散的分布方式存储在顺序表中。 散列表是一个键值对(key-item)的组合,由键(key)和元素值(item)组成。键…...
前端框架的发展史可以追溯到早期的静态网页时代
前端框架的发展史可以追溯到早期的静态网页时代。以下是前端框架的主要发展阶段: 静态网页时代:在互联网的初期,网页主要由HTML、CSS和JavaScript构成。这些网页是静态的,没有复杂的交互和动态内容。 原生JavaScript时代…...
迷宫可行路径数
题目描述 现有一个n∗m大小的迷宫,其中1表示不可通过的墙壁,0表示平地。每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。求从迷宫左上角到右下角的所有可行路径的条数。 输入描述…...

消息队列学习
消息队列是什么 消息队列:Kafka、RocketMQ、RabbitMQ等 腾讯云CMQ消息队列介绍是这么说的: 腾讯云消息队列(Cloud Message Queue,以下简称 CMQ)是分布式的消息队列服务,用于存储进程间传输的消息ÿ…...
API接口技术开发店铺详情接口采集店铺ID、卖家ID、掌柜名字、店铺名、店铺类型、店铺主页、店铺等级、店铺评分、联系方式等数据接入演示
API接口技术开发店铺详情接口采集店铺ID、卖家ID、掌柜名字、店铺名、店铺类型、店铺主页、店铺等级、店铺评分、联系方式等数据,可以按照以下步骤进行接入演示: 注册并获取API密钥: 在电商平台的开发者中心注册账号。创建一个应用࿰…...

ffmpeg maxrate 导致转码输出的内容包含随机性
https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate 问题 领导提出了一个问题,为什么转码后的视频大小字节数据都不一样,这问到我了,一时语塞。查一下吧,没有什么资料支撑。主动试一下。 尝试 首先尝试一下直接…...

Graphpad Prism10.2.1(395) 安装教程 (含Win/Mac版)
GraphPad Prism GraphPad Prism是一款非常专业强大的科研医学生物数据处理绘图软件,它可以将科学图形、综合曲线拟合(非线性回归)、可理解的统计数据、数据组织结合在一起,除了最基本的数据统计分析外,还能自动生成统…...

Cocos Creator 2d光照
godot游戏引擎是有2d光照的,用起来感觉还是很强大的,不知道他是怎么搞的,有时间看看他们怎么实现的。 之前一直以为cocos社区里面没有2d光照的实现,偶然看到2d实现的具体逻辑,现在整理如下, 一࿱…...

5款好用的AI办公软件,一键轻松制作PPT、视频,提升工作效率!
众所周知,AI 人工智能技术已渗透到生活的方方面面,无论是很多人早已用上的智能音箱、语音助手,还是新近诞生的各种 AI 软件工具,背后都离不开 AI 人工智能技术的加持。 对于各类新生的 AI 软件工具,人们很容易「选边站…...

【MyBatis面试题】
目录 前言 1.MyBatis执行流程。 2.Mybatis是否支持延迟加载? 3.延迟加载的底层原理知道吗? 4.Mybatis的一级、二级缓存用过吗? 5.Mybatis的二级缓存什么时候会清理缓存中的数据? 总结 前言 本文主要介绍了MyBatis面试题相…...

编程界的圣经:从Scheme到JavaScript构建你的计算思维
文章目录 适读人群目 录 《计算机程序的构造和解释》(Structure and Interpretation of Computer Programs,简记为SICP)是MIT的基础课教材,出版后引起计算机教育界的广泛关注,对推动全世界大学计算机科学技术教育的发…...

智慧城市与智慧乡村:共创城乡一体化新局面
一、引言 随着科技的不断进步和城乡发展的日益融合,智慧城市与智慧乡村的建设已成为推动城乡一体化发展的新引擎。智慧城市利用物联网、大数据、云计算等先进技术,实现城市治理、公共服务、产业发展等领域的智能化;而智慧乡村则借助现代科技…...

蓝桥杯——web(ECharts)
ECharts 初体验 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><script src"echarts.js">&l…...

MySQL数据库在Windows和Linux中由于大小写默认规则不同,出现大小写问题如何解决?
Windows和Linux差异:在Windows上,lower_case_table_names默认为1,而在Linux上,默认值通常为0。因此,在Linux上更改这个设置更常见,以确保与Windows环境的兼容性或实现特定的大小写敏感性需求。 操作系统的大…...

新雀优化算法NOA求解机器人栅格地图最短路径规划,可以自定义地图(提供MATLAB代码)
一、星雀优化算法 星雀优化算法(Nutcracker optimizer algorithm,NOA)由Mohamed Abdel-Basset等人于2023年提出,该算法模拟星雀的两种行为,即:在夏秋季节收集并储存食物,在春冬季节搜索食物的存储位置。CEC2005:星雀优化算法(Nut…...

重塑语言智能未来:掌握Transformer,驱动AI与NLP创新实战
Transformer模型 Transformer是自然语言理解(Natural Language Understanding,NLU)的游戏规则改变者,NLU 是自然语言处理(Natural Language Processing,NLP)的一个子集。NLU已成为全球数字经济中AI 的支柱之一。 Transformer 模型标志着AI 新…...

【Windows】Windows 11无法连接共享打印机
Windows 11无法连接共享打印机 1.在电脑点击winr 键然后输入gpedit.msc进行回车进入本地本地组策略编辑器2.打开本地组策略-管理模板>打印机->找到配置RPC连接设置,打开3.选择“已启用”,将下面连接协议改成“命名管道上的RPC”,搞定。…...

Window10数据库崩溃启动失败,MySQL8.0.30通过data文件夹恢复数据库到Docker
背景: 昨天关机前还在使用mysql,一切正常,但今天打开电脑,发现mysql启动不起来了,老是提示端口占用,但是系统也没有新安装什么软件,而且通过查询nat命令也没发现3306端口占用。而且修改成3307等…...
【树】-Lc101-对称二叉树(一棵树是否是另一棵树的子树的变形)
写在前面 最近想复习一下数据结构与算法相关的内容,找一些题来做一做。如有更好思路,欢迎指正。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.代码 写在后面 一、场景描述 对称二叉树。给给定一个二叉树,检查它是否是镜像对称的。 例…...
在Jupyter Notebook中安装第三方库
pip vs. conda pip 可以在所有环境下安装python包。conda 可以在conda环境下安装所有包。 如果你已经安装了python,那么这个选择对你来说是非常容易的: 如果你是用Anaconda或者Miniconda安装的python,那么请使用conda命令来安装python包。如…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...