基本概念

导读
大家好,很高兴又和大家见面啦!!!
现在我们已经完成了基本数据结构的内容学习,在前面的学习中,我们一共学习了4类数据结构:
- 线性结构:顺序表、链表、栈、队列、串、数组
- 树形结构:树、二叉树、哈夫曼树、森林
- 集合:并查集
- 图:有向图、无向图、DAG图、AOV网、AOE网
从今天这个篇章开始,我们正式进入【数据结构】的第七章------查找。
在今天的内容中,我们将会学习查找的一些基本概念,下面我们就一起进入今天的内容吧!!!
一、查找
在数据集合中寻找满足某种条件的数据元素的过程称为查找。
查找的结果一般分为两种:
- 查找成功:在数据集合中找到满足条件的数据元素
- 查找失败:在数据集合中没有找到满足条件的数据元素
在我们之前学习的过程中,我们有学习过一个操作------遍历,不管是顺序表的遍历、链表的遍历、树的遍历......实际上都是在相应的数据结构依次访问每一个数据元素,而查找就是在遍历的过程中,找到特定的元素,当找到该元素后,可能就无须继续往下继续遍历了,因此查找是在遍历操作的基础上实现的一种带有特定目的的操作。
二、查找表
用于查找的数据集合称为查找表,它由同一类型的数据元素(或记录)组成。
对查找表的常见操作由:
- 查询符合条件的数据元素
- 插入、删除数据元素
这里的查找表实际上就是指的存储数据元素的某种数据结构,就比如顺序表,在顺序表中存储的数据元素都属于同一类型,在顺序表中,我们可以只进行特定元素的查找,也可以对指定的元素进行插入或删除操作。
2.1 静态查找表
若一个查找表的操作值涉及查找操作,则无须动态地修改查找表,此类查找表称为静态查找表。
适合静态查找表的查找方法由:顺序查找、折半查找、散列查找 ......
2.2 动态查找表
需要动态地插入或删除的查找表称为动态查找表。
适合动态查找表的查找方法有:二叉排序树的查找、散列查找 ......
在之前我们学习顺序表时,这一块有提到过两种分配方式:静态分配与动态分配
- 静态分配:顺序表的大小不会进行改变
- 动态分配:顺序表的大小可以通过动态分配函数进行改变
由此可以看到静态与动态的区别就是其对象是否会发生变化:
- 只需要进行查找操作的查找表中,表中的元素个数不会发生变化,因此这种查找表就是静态查找表;
- 而需要进行插入、删除操作的查找表中,表中的元素个数会随着插入/删除的操作的执行而发生变化,因此这种查找表就是动态查找表;
三、关键字
数据元素中唯一表示该元素的某个数据项的值,使用基于关键字的查找,查找结果应该是唯一的。
这里的关键字与我们在C语言中提到的关键字是两个东西:
- C语言中的关键字:指的是具有某种功能,并且可以直接使用的字符。如定义变量的数据类型关键字:
int/char/bool/float......
,循环语句的关键字:while/for/do ...... while
等等 - 查找中的关键字:指的就是查找表中的数据本身的一部分。比如在结构体中,我们以某个成员的值为关键字进行查找;在整型数组中,我们将元素的值作为关键字进行查找......
下面我们以一个实例来进一步说明:
c
typedef struct Student{
char* ID;
char* name;
int age;
}Std;
在这个结构体中,学生的名字可能会重复,学生的年龄也可能会重复,但是,学生的学号一定是唯一的,因此我们可以将学号作为关键字,用于在查找表中查找指定的学生;
在这个整型数组中:{1, 2, 3, 4, 1, 6 , 45, 10}
我们可以将元素的值作为关键字,用于在该数组中查找指定的值;
在存储这个结构体类型的查找表中,关键字就是数据元素的一部分,而在整型数组中,关键字就是数据元素本身,因此我们说,查找中的关键字就是数据元素本身的一部分;
四、平均查找长度
在查找过程中,以此查找的长度是值需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平局值,其数学定义为:
A S L = ∑ i = 1 n P i C i ASL = \sum\limits^n_{i = 1}P_iC_i ASL=i=1∑nPiCi
式中:
- n n n :查找表的长度
- P i P_i Pi :查找第 i i i 个数据元素的概率,一般认为每个数据元素的查找概率相等,即 P i = 1 n P_i = \frac{1}{n} Pi=n1
- C i C_i Ci :找到第 i i i 个数据元素所需进行的比较次数。
平均查找长度是衡量查找算法效率的最主要的指标。
为了更好的理解这个概念,下面我们以线性表和二叉排序树两种数据结构的查找操作进行理解:
1 2 3 4 5 .. n
在上述这个顺序表中,我们要查找第 i i i 个元素的概率 P i = 1 n P_i = \frac{1}{n} Pi=n1,当我们从左向右查找时,我们需要讨论两种情况:
- 查找成功 :
- 当我们要查找第 1 1 1 个元素时,需要进行 1 1 1 次关键字比较
- 当我们要查找第 2 2 2 个元素时,需要进行 2 2 2 次关键字比较
- ⋯ \cdots ⋯
- 当我们要查找第 i i i 个元素时,需要进行 i i i 次关键字比较
- ⋯ \cdots ⋯
- 当我们要查找第 n n n 个元素时,需要进行 n n n 次关键字比较
即在该顺序表中,其平均查找长度为:
A S L = 1 ∗ 1 n + 2 ∗ 1 n + ⋯ + i ∗ 1 n + ⋯ + n ∗ 1 n A S L = ( 1 + 2 + ⋯ + i + ⋯ + n ) ∗ 1 n A S L = n ∗ ( n + 1 ) 2 ∗ 1 n A S L = n + 1 2 \begin{align} ASL \notag& = 1 * \frac{1}{n} + 2 * \frac{1}{n} + \cdots + i * \frac{1}{n} + \cdots + n * \frac{1}{n} \\ ASL \notag& = (1 + 2 + \cdots + i + \cdots + n) * \frac{1}{n} \\ ASL \notag& = \frac{n * (n + 1)}{2} * \frac{1}{n} \\ ASL \notag& = \frac{n + 1}{2} \end{align} ASLASLASLASL=1∗n1+2∗n1+⋯+i∗n1+⋯+n∗n1=(1+2+⋯+i+⋯+n)∗n1=2n∗(n+1)∗n1=2n+1
- 查找失败
- 当我们要查找某个元素失败时,我们总共需要进行 n n n 次比较
即在该顺序表中,其平均查找长度为:
A S L = n ASL = n ASL=n
二叉排序树的特性为:左子树 < 根结点 < 右子树,因此在二叉排序树中进行查找时,关键字对比次数与树的高度是一致的:
- 第一层:比较1次
- 第二层:比较2次
- 第三层:比较3次
- ⋯ \cdots ⋯
- 第n层:比较n次
接下来我们以下面这棵二叉排序树为例进行说明:
1 2 3 4 5 6 7 NULL NULL NULL NULL NULL NULL NULL NULL
在上图的二叉树中,我们要查找第 i i i 个元素的概率为: P i = 1 7 P_i = \frac{1}{7} Pi=71,下面我们需要讨论两种情况:
- 查找成功
- 当我们要查找第 1 1 1 个元素时,需要进行 3 3 3 次关键字比较
- 当我们要查找第 2 2 2 个元素时,需要进行 2 2 2 次关键字比较
- 当我们要查找第 3 3 3 个元素时,需要进行 1 1 1 次关键字比较
- 当我们要查找第 4 4 4 个元素时,需要进行 3 3 3 次关键字比较
- 当我们要查找第 5 5 5 个元素时,需要进行 2 2 2 次关键字比较
- 当我们要查找第 6 6 6 个元素时,需要进行 3 3 3 次关键字比较
- 当我们要查找第 7 7 7 个元素时,需要进行 4 4 4 次关键字比较
其平均查找长度为:
A S L = 1 ∗ 1 ∗ 1 7 + 2 ∗ 2 ∗ 1 7 + 3 ∗ 3 ∗ 1 7 + 4 ∗ 1 ∗ 1 7 A S L = ( 1 + 4 + 9 + 4 ) ∗ 1 7 A S L = 18 ∗ 1 7 A S L ≈ 2.57 \begin{align} ASL \notag & = 1 * 1 * \frac{1}{7} + 2 * 2 * \frac{1}{7} + 3 * 3 * \frac{1}{7} + 4 * 1 * \frac{1}{7} \\ ASL \notag & = (1 + 4 + 9 + 4 ) * \frac{1}{7} \\ ASL \notag & = 18 * \frac{1}{7} \\ ASL \notag & \approx 2.57 \end{align} ASLASLASLASL=1∗1∗71+2∗2∗71+3∗3∗71+4∗1∗71=(1+4+9+4)∗71=18∗71≈2.57
- 查找失败
- 当查找失败时,从树的根结点开始,每一层查找失败时的关键字比较次数依次为:
- 第一层:0
- 第二层:1
- 第三层:2
- 第四层:3
- 第五层:4
- 在这棵二叉排序树中,每一层查找失败的个数依次为:
- 第一层:0
- 第二层:0
- 第三层:1
- 第四层:5
- 第五层:2
- 当查找失败时,从树的根结点开始,每一层查找失败时的关键字比较次数依次为:
可以看到,查找失败时的查找总个数为8次,因此其平均查找长度为:
A S L = 0 ∗ 0 + 0 ∗ 1 + 1 ∗ 2 + 5 ∗ 3 + 2 ∗ 4 8 A S L = 25 8 A S L = 3.125 \begin{align} ASL \notag & = \frac{0 * 0 + 0 * 1 + 1 * 2 + 5 * 3 + 2 * 4} {8} \\ ASL \notag & = \frac{25}{8} \\ ASL \notag & = 3.125 \end{align} ASLASLASL=80∗0+0∗1+1∗2+5∗3+2∗4=825=3.125
在排序二叉树中,当查找失败的次数比起查找成功的次数要多一次,因此,对于n个结点的排序二叉树,其查找失败的次数为: n + 1 n + 1 n+1。
平均查找长度的数量级可以反映一个查找算法的时间复杂度,并且为了更准确的评价一个查找算法的查找效率,我们需要同时考虑查找成功与查找失败两种情况。
结语
通过今天的学习,我们掌握了查找这一重要数据结构操作的基本概念。本文重点介绍了以下核心知识点:
-
查找的基本概念:在数据集合中寻找满足条件元素的过程,分为查找成功与查找失败两种情况
-
查找表分类:静态查找表(仅查询)与动态查找表(支持增删改查)
-
关键字的作用:唯一标识数据元素的数据项,是查找操作的依据
-
平均查找长度(ASL):衡量查找算法效率的关键指标,需要分别计算查找成功与查找失败两种情况
这些基础概念为我们后续学习各种查找算法(顺序查找、折半查找、哈希查找等)奠定了重要的理论基础。理解ASL的计算方法尤其关键,它将帮助我们在实际应用中选择最合适的查找策略。
觉得这篇博客对你有帮助吗? 如果喜欢本文内容,欢迎:
• 👍 点赞支持 - 您的认可是我持续创作的最大动力!
• 💬 评论交流 - 有任何疑问或想法欢迎在评论区留言讨论
• 📌 收藏备用 - 方便日后快速回顾查找相关的核心概念
• ➡️ 转发分享 - 将这篇文章推荐给更多需要学习数据结构的朋友
下一篇我们将深入探讨《顺序查找》的实现与优化,想要继续系统学习数据结构的朋友记得关注我哦!感谢大家的阅读,我们下期再见!💻✨