哈希表和STL —— unorderde_set/unordered_map【复习笔记】

1. 哈希表的相关概念

1.1 哈希表的定义

哈希表,又称为散列表,是根据关键字直接进行访问的数据结构。

它通过一个哈希函数(Hash Function),建立了一种关键字和存储地址间的直接映射关系,将每个关键字映射到一个固定大小的数组中的一个位置,这个位置被称为哈希地址或索引。理想情况下,散列表的查找的时间复杂度为O(1),和表中元素数量无关

1.2 哈希冲突

1.2.1 哈希冲突的定义

哈希表可能把两个或两个以上的不同关键字映射到同一个地址,这种情况就叫哈希冲突,也加散列冲突,起冲突的不同关键字,称为同义词

1.2.2 处理哈希冲突的方法

1. 线性探测法

从冲突位置开始,依次线性向后探测,直到找到下一个没有存储数据的位置(如果走到哈希表尾,则返回哈希表头)

2. 链地址法

所有元素不直接存储到哈希表中,哈希表存储指针,每数据时指针为空,当有多个关键字映射到同一个位置,将这些数据串成链表,挂在该位置下面

1.3 哈希函数

1.3.1 哈希函数的定义

将关键字映射成对应地址的函数就是哈希函数,也叫散列函数,记为 Hash(key)= Addr 

1.3.2 常见的哈希函数

1. 直接定址法

直接取关键字的某个线性函数值作为散列地址,散列函数是 Hash(key)= a * key + b(a和b为常数)

2. 除留余数法

假设哈希表的大小为 M ,通过 key 除以 M 的余数作为映射位置的下标,散列函数是 Hash(key)= key % M

注意:

1. M 取不太接近 2 的整数次幂的一个质数。( 一般来讲,将关键字范围扩大 2 倍,取大于这个范围的质数即可)

2. key 有可能为负数,取模之后也会有负数。负数补正加上模数即可,但这样的活正数和负数的操作就不同一,为了方便,同一为 模加模

无论key是正数还是负数:( key % N + N )% N

3. 其他方法

数学分析法、平方取中法、折叠法、随机数法......这些方法相对局限

2. 哈希表的具体实现

案例:维护一个数据结构,初始为空,有以下操作:

           1 x:插入元素 x

           2 x:查询元素是否在数据结构中

输入描述:第一行一个整数 n ,表示操作次数 (假设插入操作次数小于10次)

                  之后 n 行,第 i 行两个整数 op、x,表示第 op 个操作和元素 x

2.1 除留取余法(哈希函数) + 线性探测法(处理哈希冲突)

#include<iostream>
#include<cstring>
using namespace std;
//根据题目的插入操作次数的范围,找到一个合适的模数创建哈希表
//范围扩大两倍,N 是质数
const int N = 23;
int h[N];

//将哈希表的所有元素初始化为一个不会取到的值
//如果初始化为0或其他数,那可能无法辨别该数是初始数还是放入的数
//一般这个取不到的值为0x3f3f3f3f
const int INF = 0x3f3f3f3f;
void Init()
{
	memset(h, 0x3f, sizeof(h));
}

//哈希函数返回映射位置
int h_f(int x)
{
	//模加模
	int id = (x % N + N) % N;

	//线性探测法处理哈希冲突
	while (h[id] != INF && h[id] != x)
	{
		id++;
		if (id == N) id = 0;
	}
	return id;
}

//插入元素
void insert(int x)
{
	int id = h_f(x);
	h[id] = x;
}

//查找元素
bool find(int x)
{
	int id = h_f(x);
	return h[id] == x;
}
int main()
{
	Init();
	int n; cin >> n;
	while (n--)
	{
		int op, x; cin >> op >> x;
		if (op == 1)
		{
			insert(x);
		}
		else
		{
			if (find(x))cout << "yes" << endl;
			else cout << "no" << endl;
		}
	}
	return 0;
}

2.2 除留取余法(哈希函数) + 链地址法(处理哈希冲突)

该实现方法和(用数组实现树的遍历存储)中的链式前向星方法一样,本质是数组模拟链表

#include<iostream>
using namespace std;
#include<cstring>
//根据题目的插入操作次数的范围,找到一个合适的模数创建哈希表
//范围扩大两倍,N 是质数
const int N = 23;
int h[N];

//数组模拟链表
int e[N], ne[N],id;

//除留取余法
int f(int x)
{
	return (x % N + N) % N;
}

//查找元素
bool find(int x)
{
	//得到 x 对应的哈希值
	int idx = f(x);
	//遍历链表
	for (int i = h[idx]; i; i = ne[i])
	{
		if (e[i] == x) return true;
	}
	return false;
}

//插入元素
void insert(int x)
{
	//先判断该元素是否存在
	if (find(x)) return;
	int idx = f(x);
	//头插
	id++;
	e[id] = x;

	ne[id] = h[idx];
	h[idx] = id;
}

int main()
{
	int n; cin >> n;
	while (n--)
	{
		int op, x; cin >> op >> x;
		if (op == 1)
		{
			insert(x);
		}
		else
		{
			if (find(x)) cout << "yes" << endl;
			else cout << "no" << endl;
		}
	}
	return 0;
}

3. unordered_set/unordered_multiset

unordered_set 和 set(红黑树和STL——set/map)的区别是,前者使用哈希表实现,而后者使用红黑树实现。导致的结果就是存储和查找的速率不一样,以及前者无序,后者有序,其他的使用方式完全一样。

而unordered_set 和 unordered_multiset 的区别:unordered_set 不能存相同的元素而unordered_multiset 可以存相同元素

#include<iostream>
#include<unordered_set>
using namespace std;

int main()
{
	int arr[] = { 3,5,6,8,9,2,10,1 };
	unordered_set<int> mp;

	//begin/end:迭代器,可以用范围for遍历哈希表
	//和红黑树实现的 set 不同,遍历出来的结果是无序的
	for (auto& e : arr)
	{
		//insert:插入,时间复杂度近似为O(1)
		mp.insert(e);
	}

    //find:查找一个元素,返回迭代器
	//count:查询一个元素出现的次数,一般用来判断该元素是否在哈希表中
	//时间复杂度都近似为O(1)
	if (mp.count(3)) cout << "yes" << endl;
	else cout << "no" << endl;

	//erase:删除元素,时间复杂度近似为O(1)
	mp.erase(3);
	if (mp.count(3)) cout << "yes" << endl;
	else cout << "no" << endl;

	//size:返回哈希表中元素个数,时间复杂度O(1)
	cout << mp.size() << endl;
	
	//empty:判断哈希表是否为空,时间复杂度O(1)
	if (mp.empty()) cout << "空" << endl;
	else cout << "非空" << endl;

	return 0;
}

4. unordered_map/unordered_multimap 

unordered_map 和 map(红黑树和STL——set和map)的区别是,前者使用哈希表实现,而后者使用红黑树实现。导致的结果就是存储和查找的速率不一样,以及前者无序,后者有序,其他的使用方式完全一样。

而unordered_map 和 unordered_multimap 的区别:unordered_map 不能存相同的元素而unordered_multimap 可以存相同元素

还有一点,无论是 map 还是 unordered_map 都可以存图,但 map 的查找速率较低,而 unordered_map 的查找速率较高

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;

void test()
{
	unordered_map<int, vector<int>> mp;
	mp[1].push_back(2);
	mp[2] = { 3, 4, 5 };
	mp[3].push_back(1);
	mp[3].push_back(2);

	for (auto& p : mp)
	{
		cout << p.first << ":";
		for (auto& b : mp[p.first]) cout << b << " ";
		cout << endl;
	}
}

int main()
{
	unordered_map<string, int> mp;

	//insert:插入元素,时间复杂度近似O(1)
	//用{}将元素括起来
	mp.insert({ "lili",1 });
	mp.insert({ "kiki",2 });
	mp.insert({ "vivi",3 });

	//c++17的结构化绑定
	for (auto& [k,v] : mp)
	{
		cout << k << "编号:" << v << endl;
	}

	//operator[]:重载[],让unordered_map可以像数组一样使用
	//但operator[]可能会向 map 插入意料外的元素
	//插入时,第一个关键字为[]里内容,第二个关键字为默认值
	//会把<"hihi",0>放入
	if (mp["hihi"] == 4) cout << "hihi=4" << endl;
	else cout << "no" << endl;

	//begin/end:迭代器,用范围for遍历
	for (auto& [k, v] : mp)
	{
		cout << k << "编号:" << v << endl;
	}
	
	//erase:删除,时间复杂度近似O(1)
	mp.erase("hihi");
	
	//find:查找元素,返回迭代器
	//count:查询元素出现次数,一般用来判断元素是否在哈希表中
	//时间复杂度都近似O(1)
	if(mp.count("lili")) cout << "yes" << endl;
	else cout << "no" << endl;

	//size:求哈希表元素个数
	//empty:判断哈希表是否为空
	//时间复杂度都近似O(1)
	cout << mp.size() << endl;
	if (mp.empty()) cout << "空" << endl;
	else cout << "非空" << endl;

	
	//存图
	test();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot高校社团管理系统【附源码+文档】

???作者&#xff1a; 米罗学长 ???个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 ???各类成品Java毕设 。javaweb&#xff0c;ssm&#xff0c;springboot等项目&#xff0c;欢迎咨询。 ???程序开发、技术解答、代码讲解、文档&am…

PHP:IDEA开发工具配置XDebug,断点调试

文章目录 一、php.ini配置二、IDEA配置 一、php.ini配置 [xdebug] zend_extension"F:\wamp64\bin\php\php7.4.0\ext\php_xdebug-2.8.0-7.4-vc15-x86_64.dll" xdebug.remote_enable on xdebug.remote_host 127.0.0.1 xdebug.remote_port 9001 xdebug.idekey"…

金融项目实战

测试流程 测试流程 功能测试流程 功能测试流程 需求评审制定测试计划编写测试用例和评审用例执行缺陷管理测试报告 接口测试流程 接口测试流程 需求评审制定测试计划分析api文档编写测试用例搭建测试环境编写脚本执行脚本缺陷管理测试报告 测试步骤 测试步骤 需求评审 需求评…

期权学习与期权异动

期权异动网站 https://www.barchart.com/options/unusual-activity/stocks Delta 衡量期权价格对标的资产价格变动的敏感度的指标。它表示标的资产价格每变动一个单位&#xff0c;期权价格预期会变动多少。 取值范围&#xff1a; 看涨期权&#xff08;Call Option&#xff…

一次有趣的前后端跨越排查

进行前后端代码联调的时候&#xff0c;使用axios调用后端请求&#xff0c;因为都是本地进行联调&#xff0c;所以没有考虑跨域的问题&#xff0c;写了一个get的请求接口&#xff0c;请求后端时&#xff0c;突然跳出下面的问题&#xff1a; 错误的信息一看很像就是跨域的问题&…

创建一个简单的spring boot+vue前后端分离项目

一、环境准备 此次实验需要的环境&#xff1a; jdk、maven、nvm和node.js 开发工具&#xff1a;idea或者Spring Tool Suite 4&#xff0c;前端可使用HBuilder X&#xff0c;数据库Mysql 下面提供maven安装与配置步骤和nvm安装与配置步骤&#xff1a; 1、maven安装与配置 1…

【0011】HTML其他文本格式化标签详解(em标签、strong标签、b标签、i标签、sup标签、sub标签......)

如果你觉得我的文章写的不错&#xff0c;请关注我哟&#xff0c;请点赞、评论&#xff0c;收藏此文章&#xff0c;谢谢&#xff01; 本文内容体系结构如下&#xff1a; 本文旨在深入探讨HTML中其他的文本格式化标签&#xff0c;主要有<em> 标签、<strong> 标签、…

从零开始:H20服务器上DeepSeek R1 671B大模型部署与压力测试全攻略

前言 最近&#xff0c;我有幸在工作中接触到了DeepSeek R1 671B模型&#xff0c;这是目前中文开源领域参数量最大的高质量模型之一。DeepSeek团队在2024年推出的这款模型&#xff0c;以其惊人的6710亿参数量和出色的推理性能&#xff0c;引起了业界广泛关注。 作为一名AI基础…

mySQL复习

目录 一.写在前面 二.介绍 三.选择语句 四.内连接 五.列属性 一.写在前面 课程视频&#xff1a;【中字】SQL进阶教程 | 史上最易懂SQL教程&#xff01;10小时零基础成长SQL大师&#xff01;&#xff01;_哔哩哔哩_bilibili 课程所需资料&#xff1a; 链接&#xff1a;h…

基于SpringBoot+Vue的医院挂号管理系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

golang介绍,特点,项目结构,基本变量类型与声明介绍(数组,切片,映射),控制流语句介绍(条件,循环,switch case)

目录 golang 介绍 面向并发 面向组合 特点 项目结构 图示 入口文件 main.go 基本变量类型与声明 介绍 声明变量 常量 字符串(string) 字符串格式化 空接口类型 数组 切片 创建对象 追加元素 复制切片 map(映射) 创建对象 使用 多重赋值 控制流语句…

3.2-A-L1-2-第15讲-冒泡排序 mochen @denglexi

博观而约取 厚积而薄发 Observe extensively but select wisely; accumulate deeply but release sparingly. 每次比较两个相邻的元素&#xff0c;如果它们的顺序错误就把它 们交换过来。 每一轮进行两两比较&#xff0c;将该轮中最大/最小的值冒出来。 冒泡程序核心代码&#…

25、泛型

十二章、泛型 12-1 为何要有泛型 1、泛型&#xff1a;是一种标签。把元素的类型设计成一个参数&#xff0c;这个类型参数就叫做泛型 2、所谓泛型&#xff0c;就是允许在定义类、接口时通过一个标识表示类中 某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在…

[KEIL]单片机技巧 01

1、查看外设寄存器的值 配合对应的芯片开发手册以查看寄存器及其每一位的意义&#xff0c;可以解决90%以上的单纯的片内外设bug&#xff0c;学会如何通过寄存器的值来排外设上的蛊是嵌入式开发从小白到入门的重要一步&#xff0c;一定要善于使用这个工具&#xff0c;而不是外设…

TCP/IP 5层协议簇:网络层(IP数据包的格式、路由器原理)

目录 1. TCP/IP 5层协议簇 2. IP 三层包头协议 3. 路由器原理 4. 交换机和路由的对比 1. TCP/IP 5层协议簇 如下&#xff1a; 2. IP 三层包头协议 数据包如下&#xff1a;IP包头不是固定的&#xff0c;每一个数字是一个bit 其中数据部分是上层的内容&#xff0c;IP包头最…

免费轻巧多功能 PDF 处理工具:转换、压缩、提取一应俱全

软件技术 今天要给大家分享一款超实用的 PDF 处理工具&#xff0c;它免费又轻巧&#xff0c;如同随时待命的得力小帮手&#xff0c;功能之强大超乎想象&#xff0c;真的值得大家收藏。 这款工具是绿色版软件&#xff0c;解压后开启&#xff0c;满满的 PDF 处理功能便映入眼帘…

基于微信小程序的疫情互助平台(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;从2019年底新型冠状肺炎疫情的爆发以来&#xff0c;使很多工作的管理工作难度再上一层楼。为了在疫情期间能更好的维护信息管理&#xff0…

飞致云开源社区月度动态报告(2025年2月)

自2023年6月起&#xff0c;中国领先的开源软件公司飞致云以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源运营数据概览&…

数据库拓展操作

目录 一、截断表&#xff1a; 操作目的&#xff1a; 操作内容&#xff1a; 性能影响&#xff1a; 基本语法&#xff1a; 例子&#xff1a; 二、插入查询结果&#xff1a; 基本语法&#xff1a; 例子&#xff1a; 三、聚合函数&#xff1a; 常用函数&#xff1a; 基…

在 Mac 上使用 Docker 安装宝塔并部署 LNMP 环境

前言 只因为在mac上没有找到合适的PHP开发集成环境&#xff0c;之前有安装了Eserver&#xff0c;但是安装一些常用PHP扩展有时候还是需要手动去编译添加。phpStudy也没有找到适合Mac的版本&#xff0c;在后面安装了Parallels Desktop虚拟机 来运行Ubuntu系统搭建了一套LNMP环境…