目录
一、队列
1.定义
2.应用
3.分类
(1)逻辑结构
(2)物理结构
顺序队列
链式队列
二、哈希存储
1.定义
2.哈希冲突
(1)开放定址法
(2)再哈希法
(3)链地址法
三、练习
1.链式队列
(1)创建队列
(2)入队(尾插)
(3)出队(头删)
(4)遍历打印
(5)清空队列
(6)销毁队列
(7)获取队头元素
2.哈希表
(1)创建哈希表
(2)设计哈希函数
(3)插入数据(头插)
(4)遍历打印
(5)查找(按姓名)
(6)清空哈希表
一、队列
1.定义
之前我们提到过的队列结构,也是一种线性存储的数据结构。
队列:从一端进行数据插入,另一端进行数据删除的线性存储结构。
队列均遵循FIFO,即先进的先出、后进的后出。
2.应用
缓冲区,缓存数据
3.分类
(1)逻辑结构
从逻辑结构上看,队列均为线性结构。
(2)物理结构
从物理结构上看,队列分为顺序队列与链式队列。
-
顺序队列
队头指向第一个元素,队尾指向最后一个元素后的空位置。
出队时队头向后移动,入队时队尾向后移动。
注:普通的顺序队列会出现“假溢出”的问题,即当队尾移动到队列外时,认为队列以满,数据溢出,但实际上队列空间并未用尽,造成内存浪费。
为解决“假溢出”问题,我们一般使用循环链表,即队列头尾相接。
1. 空队列:队头和队尾相遇
2. 满队列:(tail+1) 和队头在同一位置(牺牲了一个存储空间)
-
链式队列
链式队列即要求每个数据均有指针域,指向下一个元素。
循环队列与链式队列的比较:从时间上看,它们的时间复杂度均为O(1)。不过循环队列需事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则两者还是有细微差异。
从空间上来看,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列不存在这个问题,尽管它需要一个指针域,会产生一些空间上的开销,但可以接受。所以在空间上,链式队列更加灵活。
总的来说,在可以确定队列长度最大值的情况下,建议用循环队列,如果你无法预估队列的长度时,则用链式队列。
二、哈希存储
1.定义
哈希存储,也称散列存储:将要存储数据的关键字和数据的存储位置之间建立对应的函数关系,即哈希函数。
哈希存储的目的是为了提高数据的查找效率。哈希存储的表现方式是哈希表。
哈希表:一段连续内存空间。
存储数据时,按照函数关系寻找存储位置;数据查找时,根据关键字进行函数映射得到数据的存储位置。
2.哈希冲突
哈希冲突,也称哈希矛盾,是指多个不同的输入值通过哈希函数处理后得到相同的输出值,这种情况在使用哈希表时经常发生。
为了解决这个问题,开发者们提出了多种方法,主要包括以下几种:
(1)开放定址法
开放定址法是一种在发生冲突时寻找另一个空闲地址的方法。这种方法的具体实现有多种,包括线性探测法、平方探测法等。
线性探测法是当发生冲突时,顺序查看表中下一个单元,直到找到空闲单元。平方探测法则是在冲突发生的位置前后进行跳跃式探测。
(2)再哈希法
再哈希法是构造多个不同的哈希函数,当发生冲突时,使用第二个、第三个等其他哈希函数计算新的地址,直到找到不冲突的地址为止。这种方法可以减少聚集现象,但会增加计算时间。
(3)链地址法
链地址法是将所有哈希地址相同的记录链接在同一链表中。当发生冲突时,冲突的元素将被添加到链表的末尾。这种方法适用于频繁插入和删除操作的场景。
三、练习
1.链式队列
(1)创建队列
(2)入队(尾插)
(3)出队(头删)
(4)遍历打印
(5)清空队列
(6)销毁队列
用valgrind工具验证销毁结果
(7)获取队头元素
2.哈希表
(1)创建哈希表
(2)设计哈希函数
(3)插入数据(头插)
(4)遍历打印
(5)查找(按姓名)
(6)清空哈希表
用valgrind工具查看清空结果