数据结构导论【六】之 查找表

article/2025/9/16 23:49:07

感谢内容提供者:金牛区吴迪软件开发工作室
接上一篇:数据结构导论【五】之 图

文章目录

  • 一、基本概念
  • 二、静态查找表的实现
    • 1.顺序表上的查找 -- 顺序查找
      • a.过程
      • b.算法
      • c.算法分析
    • 2.有序表上的查找 -- 二分查找
      • a.二分查找思想
      • b.二分查找过程
      • c.二分查找算法
      • d.例:(在下列有序顺序表中查找 K = 18)
      • e.算法分析
    • 3.索引顺序表的查找 -- 分块查找
      • a.查找过程
      • b.例
      • c.算法分析
  • 三、动态查找表(二叉排序树)
    • 1.二叉排序树
    • 2.二叉排序树上的查找
      • a.过程
      • b.二叉排序树查找算法
      • c.二叉排序树的插入和生成
  • 四、散列表(哈希表)
    • 1.常用散列法
      • a.数字分析法
      • b.除留余数法
      • c.平方取中法
      • d.基数转换法
    • 2.处理冲突的几种方法
      • ①链地址法
      • ②线性探测法
      • ③二次探测法:
      • ④多重散列法
      • ⑤公共溢出区法
      • ⑥总结
  • 五.小结

一、基本概念

查找表 – 由同一类型的数据元素(或记录)构成的集合。
关键字(键) – 用来标识数据元素的数据项称为关键字,简称;其值称为键值
主关键字 – 可唯一标识各个数据元素的关键字
查找 – 根据给定的某个k值,在查找表寻找一个其键值等于k的数据元素。
静态查找表 – 进行的是引用型运算
动态查找表 – 进行的是加工型运算。

分类操作
静态查找表建表、查找、读表中元素
动态查找表初始化、查找、读表中元素、插入、删除

二、静态查找表的实现

const int maxsize = 20; // 静态查找表的表长
typedef struct {TableElem elem[maxsize + 1]; // 一维数组,0号单元留空int n; // 最后一个元素的下标,也即表长
} SqTable;typedef struct {keyType key; // 关键字域... // 其他域
} TableElem;

1.顺序表上的查找 – 顺序查找

a.过程

从表中最后一个记录开始顺序进行查找,若当前记录的关键字等于给定值,则查找成功;否则,继续查上一记录…;若直至第一个记录尚未找到需要的记录,则查找失败

b.算法

方法一:使用一种设计技巧:设立岗哨

int SearchSqtable(Sqtable T, KeyType key) {// 在顺序表R中顺序查找其关键字等于key的元素。// 若找到,则函数值为该元素在表中的位置,否则为0.T.elem[0].key = key;i = T.n;while(T.elem[i].key != key) i--;return i;
}

c.算法分析

成功查找:ASL = (n + 1) / 2
不成功查找:ASL = n + 1


顺序查找优点:简单,对表无要求;
顺序查找缺点:比较次数多。


2.有序表上的查找 – 二分查找

a.二分查找思想

二分查找的前提条件:顺序方式存储、且元素按关键字有序。


二分查找的逻辑步骤
每次找中项,中项是的话,则找到;
中项不是的话,根据此中项的关键字与给定关键字的关系,决定在表的前或后半部继续找。

关键点:可使下次查找范围缩小一半。


b.二分查找过程

表头指针low = 1,表尾指针high = n。
1.求中间点:mid = (low + high) / 2; // 结果向下取整,抛弃小数部分
{item[1], …, item[mid - 1], item[mid], item[mid + 1], …, item[n]}
2.给定关键字k与中项记录关键字比较
①K < item[mid].key,则所查记录落在表的前半部;继续在前半部找,此时low不变,high = mid - 1
②K = item[mid].key,则查找成功,中项即是,结束;
③K > item[mid].key,则所查记录落在表的后半部;继续在后半部找,此时low = mid + 1,high不变
3.若low <= high,则转(1),否则查找不成功。

c.二分查找算法

int SearchBin(SqTable T, KeyType key) {// 在有序表R中二分查找其关键字等于K的数据元素;若找到,则返回改元素在表中的位置,否则返回0int low, high;low = 1;high = T.n;while (low <= high) {mid = (low + high) / 2;if (key == T.elem[mid].key) {return mid;} else if (key < T.elem[mid].key) {hight = mid - 1;} else {low = mid + 1;}}return 0;
}

d.例:(在下列有序顺序表中查找 K = 18)

在这里插入图片描述

e.算法分析

查找成功时:比较次数最多为 log2n 向下取整 + 1
查找失败时:比较次数最多也为 log2n 向下取整 + 1

二分查找算法每进行一次键值与给定值的比较,查找区间的长度至少减小为原来二分之一,『二分查找』由此得名。由此易推算出二分查找的查找长度不超过log2n 向下取整 + 1

二分查找的平均查找长度为:
在这里插入图片描述
当n较大时可得:
在这里插入图片描述


由此可见,二分查找的时间性能比顺序查找好。而相比顺序查找而言,二分查找要求表元素是排好序的。当采用的存储结构不是顺序表,或者顺序表中元素未按键值的次序(递增或递减)排列时,则不能进行二分查找。


3.索引顺序表的查找 – 分块查找

a.查找过程

  1. 先建立最大(或小)关键字表 – 索引表(有序)
    即将每块中最大(或最小)关键字及指示块首记录在表中位置的指针依次存入一张表中,此表称为索引表;
  2. 查找索引表,以确定所查元素所在块号;
    将查找关键字k与索引表中每一元素(即各块中最大关键字)进行比较,以确定所查元素所在块号;
  3. 在相应块中按顺序查找关键字为k的记录。

b.例

在这里插入图片描述
在这里插入图片描述

c.算法分析

分块查找的平均长度等于俩阶段各自的查找长度之和。若每块含S个元素,且第一阶段采用顺序查找,则在等概率假定下,分块查找的平均查找长度为
在这里插入图片描述
其中,n为顺序表中的数据元素数目。当s取 n \sqrt{n} n 时,ASLbs达到最小值 n + 1 \sqrt{n + 1} n+1

静态查找表的上述三种不同实现各有优缺点。
其中:
顺序查找效率最低,但限制最少。
二分查找效率最高,但限制最强。
而分块查找则介于上述二者之间。
在实际应用中应根据需要加以选择。


三、动态查找表(二叉排序树)

表结构是在查找过程中动态生成的;对于给定值k,若表中存在其关键字等于k的记录,则查找成功返回,否则在表中插入关键字等于k的记录。

1.二叉排序树

一颗二叉排序树(Binary Sort Tree)(又称二叉查找树)或者是一颗空二叉树,或者是具有下列性质的二叉树;
①若它的左子树不空,则左子树上所有结点的键值均小于它的根结点键值;
②若它的右子树不空,则右子树上所有结点的键值均大于它的根结点键值;
③根的左、右子树也分别为二叉排序树。


性质:
中序遍历一颗二叉排序树所得的结点访问序列是键值的递增序列。


2.二叉排序树上的查找

a.过程

当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功;否则根据给定值与根结点关键字间的大小关系,分别在左子树或右子树上继续进行查找。


b.二叉排序树查找算法

注:
1.二叉排序树,对每个结点,均有:
左子树上的所有结点键值都比根的小;
右子树上的所有结点键值都比根的大。
2.构造二叉排序树的同时也对序列排序了。

BinTree SearchBST(BinTree bst, KeyType key) {// 在根指针bst所指的二叉排序树上递归地查找键值等于key的结点。若成功,则返回指向该结点的指针,否则返回空指针// 不成功时返回NULL作为标记if (bst == NULL) {return NULL;} else if (key == bst -> key) { // 成功时返回结点地址return bst;} else if (key < bst -> key) { // 继续在左子树中查找return SearchBST(bst -> lchild, key);} else { // 继续在右子树中查找return SearchBST(bst -> rchild, key); }
}

PS:由上面的查找过程可知:在二叉排序树上进行查找,若查找成功,则是从根结点出发走了一条从根结点到待查结点的路径;若查找不成功,则是从根节点出发走了一条从根到某个叶子的路径。因此与二分查找类似,关键字比较的次数不超过二叉树的深度。

c.二叉排序树的插入和生成

对序列R={k1, k2, …, kn}, k1 ~ kn均为关键字值,则按下列原则可构造二叉排序树:
1.令k1为根;
2.若k1 < k2,则令k2为k1的右孩,否则为左孩;
3.k3,k4,…kn递归重复(2)


例题:查找键值序列为{50, 48,24, 55, 53, 50, 90},则生成的二叉排序树如图6-6所示。
在这里插入图片描述


二叉排序树的查找分析:
二叉排序树上的平均查找长度是介于O(n)和O(log2n)之间的,其查找效率与树的形态有关。

假设5个元素的查找概率相等均为 1 5 {\frac 15} 51
则图6-7 a的平均查找长度为ASL(a) = 1 + 2 + 2 + 3 + 3 5 {\frac {1+2+2+3+3}5} 51+2+2+3+3 = 11 5 {\frac {11}5} 511
在这里插入图片描述

需要在二叉排序树的动态变化过程中随时调整其形态,使之保持『平衡』。二叉排序树的平均查找长度 ASL <= 1 + log2n。


四、散列表(哈希表)

散列函数(哈希函数) – 设记录表A,长为n,ai(1 <= i <= n)为表中某一元素,ki为其关键字,则关键字ki和元素ai在表中的地址之间有一函数关系,
即: Addr(ai) = H(Ki)

ai在表中地址。
散列函数:关键字与元素地址的函数

为了使数据元素的存储位置和键值之间建立某种联系,以减少比较次数,可以用散列技术实现动态查找表。

散列地址 – 由散列函数决定数据元素的存储位置,该位置称为散列地址。


散列查找
在这里插入图片描述

散列表 – 通过散列法建立的表称为散列表。

冲突
k1 != k2 但H(k1) = H(k2)的现象称为冲突
即:不同的关键字映射到同一存储单元。
并称k1和k2是同义词


散列法主要工作
1.选择一个好的散列函数
2.解决冲突


PS:函数计算简便,运算速度快
随机性好,地址尽可能均匀分布
冲突小

1.常用散列法

a.数字分析法

在这里插入图片描述

b.除留余数法

散列函数:取关键字被某个不大于散列表长m的数p除后所得余数作为散列地址。
即:H(key) = key mod p (p <= n)


方法关键 – 如何取p?
结论:
①p不取偶数
②p不取关键字字符基的n倍
③一般选p为质数且最接近表长m的质数


c.平方取中法

平方取中法以键值平方的中间几位作为散列地址。这一方法计算简单,是一种较常用的构造散列函数的方法,通常在选定散列函数时不一定能知道键值的分布情况。取其中哪几位也不一定合适,而一个数平方的中间几位与这个数的每一位都有关,所得散列地址比较均匀。


d.基数转换法

在这里插入图片描述

2.处理冲突的几种方法

①链地址法

用『链地址法』处理冲突
思想 : 将散列地址相同记录存储在同一单链表中(称同义词表),同时按散列地址设立一个表头指针向量。


链地址是对每一个同义词都建一个单链表来解决冲突,其组织方式如下:
设选定的散列函数为H,H的值域(即散列地址的范围)为 0 ~(n - 1)。设置一个『指针向量』Pointer HP[n],
其中的每个指针HP[i]指向一个单链表,该单链表用于存储所有散列地址为i的数据元素。每一个这样的单链表称为一个同义词子表。

例如,若选定的散列函数为H(key) = key mod 13,已存入键值为26、41、25、05、07、15、12、49、51、31、62的散列表,如图6-10所示。
在这里插入图片描述


②线性探测法

用『线性探测法』处理冲突构造散列表
思想: 计算出的散列地址已被占用,则按顺序找"下一个"空位。
过程: 设有散列表HT(向量),对给定记录R,其关键字k,对应哈希地址H(k) => j
在这里插入图片描述

要点:
①HT[j]空,则R填入;
②HT[j].key = k,则输出;
③否则,按顺序一步步找『下一个』空位,将R填入。

例:已知一组关键字为(13, 41, 15, 44, 06, 68, 25,12,38,64,19,49),按散列函数H(key) = key mod 13 和 线性探测法 处理冲突构造散列表。
在这里插入图片描述


散列法的优缺点:
优点:直接由关键字通过哈希函数计算出哈希地址,查找效率高;
缺点:常发生冲突,影响查找效率。


③二次探测法:

二次探测法的基本思想:生成的后继散列地址不是连续的,而是跳跃式的,以便为后续数据元素留下空间从而减少堆积。按照二次探测法,键值key的散列地址序列为d0=H(key);

di = (d0 + i) mod m;

其中,m 为散列表的表长, i = 12, -12, 23,…,± k2(k <= m / 2)。

例题:
如图 6-9 所示长度为13的散列表中,用二次探测法插入键值为29的元素。
在这里插入图片描述

分析:当发生冲突时,应用二次探测法,得到下一个地址d1 = (3 + 12) mod 13 = 4仍冲突,则再求下一个地址d2 = (3 - 12) mod 13 = 2仍冲突,直到散列地址为d3 = (3 + 22) mod 13 = 7时其位置上没有元素,即元素填入散列表中序号为7的位置。

二次探测法的缺点是不易探测到整个散列表的所有空间,也就是说,上述后继散列地址可能难以包括散列表的所有存储位置。


④多重散列法

此法要求设立多个散列函数Hi, i = 1, …, k。当给定值 key 与散列表中的某个键值是相对于某个散列函数式的同义词而发生冲突时,继续计算这个给定值key在下一个散列函数Hi+1下的散列地址,直到不再产生冲突为止。这种方法的优点是不易产生 『堆积』 ,缺点是计算量较大


⑤公共溢出区法

按这种方法,散列表由俩个一维数组组成。一个称为基本表,它实际上就是上面所说的散列表,另一个称为溢出表。插入首先在基本表上进行,假如发生冲突,则将同义词存入溢出表。这样,基本表不可能发生『堆积』。


⑥总结

常用散列法:数字分析法、除留余数法、平方取中法、基数转换法。

散列表解决冲突的方法:线性探测法、二次探测法、链地址法、多重散列法、公共溢出区法。


五.小结

熟练掌握顺序表和有序表的查找方法和算法

掌握二叉排序树的定义、构建方法和查找方法;

什么是散列方法、什么是冲突?

熟练掌握散列表的构造和查找及冲突的处理

按定义计算各种查找方法在等概率情况下查找成功的平均查找长度。




下一篇:数据结构导论【七】之 排序


http://chatgpt.dhexx.cn/article/VrBhd0DW.shtml

相关文章

查找表(Lookup table)

查找表&#xff08;look-up-table&#xff09;这个名字很好听&#xff0c;缩写 LUT&#xff0c;听起来很高端&#xff0c;其实是一种很简单高效的索引操作&#xff0c;今天简单介绍一下。 是啥 wiki定义&#xff1a; a lookup table is an array that replaces runtime computa…

从底层结构开始学习FPGA(2)----LUT查找表

文章目录 系列目录与传送门 一、概述 二、实现原理 系列目录与传送门 《从底层结构开始学习FPGA》目录与传送门 一、概述 记得刚接触FPGA的时候&#xff0c;总能看见类似这样的一句话----FPGA是基于查找表LUT的可编程逻辑器件。FPGA常常被人比作“数字积木”&#xff0c;就是因…

码,主码,主属性,非主属性,平凡函数依赖,完全依赖等词解释

码&#xff1a;代表数目的符号 主码 我们在建立数据库的时候&#xff0c;需要为每张表指定一个主码&#xff0c;主码也叫主键。 所谓主码就是在实体集中区分不同实体的候选码。 一个实体集中只能有一个主码&#xff0c;但可以有多个候选码。 必须注意两点&#xff1a; 1.主…

SpringBoot项目打jar后执行jar包提示:xx没有主属性清单 解决

SpringBoot项目打jar包后执行jar包提示&#xff1a;xx没有主属性清单 解决 今天在练习SpringBoot项目打jar包部署的时间遇见了一个问题&#xff1a;jar中没有主属性清单&#xff0c;对此也是比较疑惑&#xff0c;在百度之后找到了解决方式 主属性清单是jar包中MANIFEST.MF文件中…

【图示化】SQL Server概念:超键(码)、候选键(候选码)、主键(主码)、主属性与非主属性、外键

关系模型概念 字段属性名&#xff0c;每一行就是一条记录一个元组&#xff0c;每个单元格就是一个分量&#xff0c; 主键&#xff0c;外键 主码主键主关键字 超键&#xff08;码&#xff09;&#xff0c;候选键 码超键 超键 &#xff08;唯一的&#xff0c;可多余&#xff09; …

候选码、主码、全码、外码、主属性、主键、主关键字、非主属性

一、讲解 首先说明 键字码字&#xff0c;所以 主键主码主关键字&#xff0c;候选键候选码候选关键字… 所谓关系键&#xff0c;指的是一个表中的一个&#xff08;或一组&#xff09;属性&#xff0c;用来标识该表的每一行或与另一个表产生联系。 话不多说&#xff0c;上图&a…

软考系列之候选码,主码,主属性,非主属性详讲

候选码&#xff0c;主码&#xff0c;主属性&#xff0c;非主属性详讲 文章目录 目录 文章目录 前言 一、候选码&#xff0c;主码&#xff0c;属性&#xff0c;非主属性的定义 二、具体题目 三、补充 前言 软考刷题&#xff0c;遇到这系列的题目&#xff0c;对我来讲&#xff0…

数据库中主键、主码、主属性、关键字、候选关键字、码的区别

码是数据库系统中的基本概念&#xff0c;所谓码就是能唯一标识实体的属性&#xff0c;它是整个实体集的性质&#xff0c;而不是单个实体的性质。它包括超码、候选码和主码。 &#xff08;1&#xff09;超码是一个或多个属性的集合&#xff0c;这些属性可以让我们在一个实体集中…

函数依赖 主码 主属性 非主属性 候选键 超键 详解

最近做项目要搞数据库看到范式那一节头脑发晕&#xff0c;概念都忘了&#xff0c;于是从网上搜罗并整理一下&#xff1b; 函数依赖部分参考&#xff1a;https://blog.csdn.net/jsj13263690918/article/details/79796275 主码&#xff1a;主关键字&#xff08;主键&#xff0c;…

c语言memset详解

目录 1 函数声明1.1功能1.2 例子 2 常见错误2.1 搞反了 ch 和 n 的位置.2.2 过度使用memset2.3 3 特殊例子 1 函数声明 void *memset(void *s, char ch, unsigned n);1.1功能 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值。块的大小由第三个参数指定,作…

【Java基础知识 9】序列化与反序列化

🍅 Java学习路线:搬砖工逆袭Java架构师 🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪 🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 面试官:兄弟,说说你对transient的理解和感悟 …

详解序列化与反序列化

一、什么是序列化与反序列化 序列化时将对象状态转换为可保持或传输的形式的过程。序列化的补集是反序列化&#xff0c;反序列化是将流转换为对象。两个过程一起保证能够存储和传输数据。 .NET具有以下三种序列化技术&#xff1a; 1.二进制序列化 保持类型保真&#xff0c;这…

为什么要序列化?序列化你知道哪些?

凡事都要问为什么&#xff0c;在讲解序列化概念和原理前&#xff0c;我们先来了解一下为什么需要序列化。 为什么要序列化&#xff1f; 如果光看定义我想你很难一下子理解序列化的意义&#xff0c;那么我们可以从另一个角度来感受一下什么是序列化。 都玩过游戏么&#xff1…

说说什么是序列化,如何实现序列化

分析&回答 序列化机制 序列化机制&#xff08;包括序列化和反序列化&#xff09;的本质是用流将对象读到内存和写入外存。序列化机制的意义就是将对象脱离程序运行独立存在。通过网路或跨平台传输对象&#xff0c;传递的参数与返回值都实现序列化机制。实现序列化需要实现…

java序列化详解

一、序列化与反序列化 序列化&#xff1a;指堆内存中的java对象数据&#xff0c;通过某种方式把对存储到磁盘文件中&#xff0c;或者传递给其他网络节点&#xff08;网络传输&#xff09;。这个过程称为序列化&#xff0c;通常是指将数据结构或对象转化成二进制的过程。 即将对…

序列化和反序列化的底层实现原理是什么?

序列化和反序列化作为Java里一个较为基础的知识点&#xff0c;大家心里也有那么几句要说的&#xff0c;但我相信很多小伙伴掌握的也就是那么几句而已&#xff0c;如果再深究问一下Java如何实现序列化和反序列化的&#xff0c;就可能不知所措了&#xff01;遥记当年也被问了这一…

序列化和反序列化

我以前确实对序列化&#xff0c;乃至现在也是不是很熟悉&#xff0c;有时候查找资料&#xff0c;但依旧懵懵懂懂&#xff0c;不过还好遇到一个博主&#xff0c;确定写的挺好的&#xff0c;链接会放再底部 废话不多说&#xff0c;先看官网定义&#xff1a; 序列化 (Serializat…

我把序列化玩成了这样,吊锤了一波面试官

我们都知道&#xff0c;新建一个对象的时候实现 Serializeable 接口&#xff0c;但为什么要这么做&#xff1f;什么时候这样子做&#xff1f;这样子做会不会出现幺蛾子&#xff1f;阿粉一个三连差点把自己都问懵逼了…… 那接下来&#xff0c;大家就和阿粉一起简单了解一下这个…

什么是序列化? 如何实现(反)序列化 序列化的应用

1. 什么是序列化与反序列化&#xff0c;什么情况需要序列化1.1 序列化序列化是什么序列化的目的什么情况需要序列化 1.2 反序列化反序列化是什么反序列化的目的 2. Java中的序列化与反序列化2.1 如何实现序列化Java序列化的规定序列化的API实现(反)序列化的示例对象在硬盘上的存…

1.传输线驻波比

Transmission Line & Active Voltage Standing Wave Ratio 1.1 信号完整性概述 数字电路的出现极大地提高了电子产品的抗干扰能力&#xff0c;随着电路的工作频率不断提高&#xff0c;这种抗干扰能力逐渐显得有些“力不从心”。特别是在高速电路的范畴&#xff0c;“理想互…