数据结构—查找

查找的基本概念

基本概念

查找表其实并不是某一种特定的指定的数据结构,它只是对于要执行查找操作的这个数据结构的一个统称。

用不同的数据结构存储这些数据也会影响到查找算法的实现还有相关的效率

查找算法的效率优化

平均查找长度(Average Search Length, ASL)是衡量数据结构查找效率的一个重要指标。它表示在查找过程中,平均需要比较多少次才能找到目标元素。ASL的计算方法因数据结构的不同而异,但基本原理是相同的。

定义

平均查找长度(ASL)是指在查找过程中,成功查找和不成功查找的平均比较次数。通常分为两种情况:

  1. 成功查找的ASL(ASL_success):在查找过程中找到目标元素所需的平均比较次数。
  2. 不成功查找的ASL(ASL_failure):在查找过程中未找到目标元素所需的平均比较次数。
计算方法
成功查找的ASL

假设在一个数据结构中有 nn 个元素,每个元素的查找概率分别为 p1,p2,...,pnp1​,p2​,...,pn​,查找每个元素所需的比较次数分别为 c1,c2,...,cnc1​,c2​,...,cn​,则成功查找的ASL可以表示为:

ASL_success=∑i=1npi⋅ciASL_success=∑i=1n​pi​⋅ci​

其中:

  • pipi 是查找第 ii 个元素的概率。
  • cici 是查找第 ii 个元素所需的比较次数。
不成功查找的ASL

假设在一个数据结构中进行不成功查找时,每次查找需要的比较次数分别为 c1,c2,...,cmc1​,c2​,...,cm​,每种情况的概率分别为 q1,q2,...,qmq1​,q2​,...,qm​,则不成功查找的ASL可以表示为:

ASL_failure=∑i=1mqi⋅ciASL_failure=∑i=1m​qi​⋅ci​

其中:

  • qiqi 是不成功查找第 ii 种情况的概率。
  • cici 是不成功查找第 ii 种情况所需的比较次数。
示例
示例1:线性表

假设有一个线性表,包含元素 {10, 20, 30, 40, 50},查找每个元素的概率相等,即 p1=p2=p3=p4=p5=15p1​=p2​=p3​=p4​=p5​=51​。查找每个元素所需的比较次数分别为 1, 2, 3, 4, 5。

计算成功查找的ASL:

ASL_success=15⋅1+15⋅2+15⋅3+15⋅4+15⋅5ASL_success=51​⋅1+51​⋅2+51​⋅3+51​⋅4+51​⋅5 ASL_success=15(1+2+3+4+5)ASL_success=51​(1+2+3+4+5) ASL_success=155=3ASL_success=515​=3

示例2:二叉搜索树

假设有一个二叉搜索树,包含元素 {10, 20, 30, 40, 50},查找每个元素的概率相等,即 p1=p2=p3=p4=p5=15p1​=p2​=p3​=p4​=p5​=51​。查找每个元素所需的比较次数分别为 1, 2, 3, 2, 3。

计算成功查找的ASL:

ASL_success=15⋅1+15⋅2+15⋅3+15⋅2+15⋅3ASL_success=51​⋅1+51​⋅2+51​⋅3+51​⋅2+51​⋅3 ASL_success=15(1+2+3+2+3)ASL_success=51​(1+2+3+2+3) ASL_success=115=2.2ASL_success=511​=2.2

影响因素
  1. 数据结构的选择:不同的数据结构(如数组、链表、二叉搜索树、哈希表等)会影响ASL。
  2. 元素的分布:元素的分布(均匀分布、非均匀分布等)会影响查找概率。
  3. 查找算法:不同的查找算法(如顺序查找、二分查找、散列查找等)会影响比较次数。
结论

平均查找长度(ASL)是评估数据结构和查找算法效率的重要指标。通过计算ASL,可以比较不同数据结构和算法的性能,选择最适合特定应用场景的数据结构和算法。

顺序查找

算法思想

顺序查找,又称"线性查找",通常用于线性表

思想:从头到jio挨个找(或者反过来)

算法实现

在这段代码中,"哨兵"是一种优化顺序查找的技术。具体来说,它是通过在查找表的第一个位置放置一个特殊的值(在这里是待查找的关键字key),使得查找过程可以从最后一个元素向前遍历,直到找到匹配的元素为止。

哨兵的作用
  1. 简化循环条件:通过在第一个位置放置哨兵,可以简化查找循环的终止条件。原本需要判断当前索引是否越界以及当前元素是否等于关键字,现在只需要判断当前元素是否等于关键字即可。

    复制代码
    for(i=ST.TableLen; ST.elem[i]!=key; --i); 

    这里不需要再额外检查索引是否小于零,因为哨兵的存在保证了循环一定会结束。

  2. 提高查找效率:虽然这种技术不会显著改变最坏情况下的时间复杂度(仍然是O(n)),但在某些情况下可以减少不必要的比较次数。例如,当关键字位于表的后半部分时,哨兵技术可以直接跳过前面的所有元素,直接从后往前查找。

实现细节
  1. 初始化哨兵:首先将关键字赋给表的第一个元素。

    复制代码
    ST.elem[0] = key;
  2. 查找过程:从表的最后一个元素开始,逐个向前比较,直到找到与哨兵相同的关键字。

    复制代码
    int i;
    for(i=ST.TableLen; ST.elem[i]!=key; --i);
  3. 返回结果:如果找到了匹配的关键字,则返回其下标;如果没有找到,则返回0(这里假定0表示查找失败)。

    复制代码
    return i;
注意事项

尽管哨兵技术可以简化代码和提高一些场景下的查找速度,但它也有一些局限性和需要注意的地方:

  • 空间开销:哨兵技术需要额外的空间存储哨兵,这可能会增加内存消耗。
  • 适用范围:这种方法主要适用于静态查找表,对于动态变化的表可能不太合适,因为它涉及到频繁修改表的第一个元素。

总的来说,哨兵技术是一种简单有效的优化策略,特别是在编写简洁高效的代码时非常有用。

算法优化

折半查找

算法思想

算法实现

基于升序,如果是降序的话,具体语句可能不同

查找判定树

折半查找的判定树中,若mid=(low+high)/2,则对于任何一个结点,必有:

右子树结点树-左子树结点数=0或1

折半查找的判定树一定是平衡二叉树

包含失败结点的话就是h+1

折半查找效率

如果是向上取整的话,刚好相反 左子树结点树-右子树结点数=0或1

注意mid是向上取整还是向下取整

分块查找

算法思想

查找效率分析(ASL)

这块是分析,上面是得出的结论

是4不是5呀呀呀呀 而且三次索引,一次块内

二叉排序树(BST)

二叉排序树的定义

可以让各个结点包含更复杂的信息,需确定好各个结点之间比较大小的规则,上面这是一种非递归的实现

查找操作

插入操作

也有可能得到不同款二叉排序树

删除操作

先搜索找到目标结点:

1.若被删除结点z是叶结点,则直接删除,不会破环二叉排序树的性质。

左子树结点值<根结点值<右子树结点值

2.若结点z只有一颗左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。

  1. 直接后继

直接前驱

查找效率分析

平衡二叉树

定义

插入操作

在插入操作中,只要将最小不平衡子树调整平衡,则其他祖先结点都会恢复平衡

插入新结点后如何调整"不平衡"问题

假定所有子树的高度都是H(BL、BR、AR都是H,后面可以自己分析推导一下)

这个是LL的前提条件

就是把黄色框里中间的作根结点,重新生成一个平衡树!!就是旋转的结果了(通用)

也有可能是插入到C的右子树,不影响,处理过程都是一样的

查找效率分析

查找效率主要影响来自于树的高度

平衡二叉树的删除

前驱和后继、同样高度的孙子哪种选择都可以

红黑树的定义和性质

二叉排序树、平衡二叉树、红黑树都是适合于查找的二叉树

红黑树是一种自平衡的二叉查找树,其设计目的是为了保证树的平衡性,使得树的操作(如查找、插入和删除)都能在对数时间内完成。红黑树通过给每个节点添加一个存储位来表示节点的颜色(红色或黑色),并通过一系列的规则来维持树的平衡性。以下是红黑树的几个重要特性:

  1. 每个节点要么是红色的,要么是黑色的。
  2. 根节点总是黑色的。
  3. 每个叶子节点(NIL节点,空节点)是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。(从任何一个节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)
  5. 从任一节点到其每个叶子的所有路径都包含相同数量的黑色节点。

关于"红黑树的根节点一定是黑色的",这是出于以下几个原因:

  • 避免连续的红色节点:红黑树的一个关键规则是不允许存在两个连续的红色节点。如果根节点是红色的,那么它就没有父节点来确保这条规则的遵守了,因为没有父节点可以是黑色来打断连续的红色节点。
  • 保持黑色高度的一致性:黑色高度是指从某个节点到其任意一个叶子节点路径上黑色节点的数量。保持所有路径的黑色高度一致有助于维持树的平衡。如果根节点是红色,那么从根节点开始计算的黑色高度就会比其他路径少一个单位,破坏了黑色高度的一致性。
  • 简化实现:规定根节点为黑色可以简化一些算法的实现。例如,在插入或删除操作导致树失衡时,调整过程会涉及到颜色的变化和旋转等操作。如果根节点总是黑色,那么在进行这些操作时就不必担心根节点的颜色变化带来的额外复杂性。

因此,红黑树的根节点总是黑色的这一规则,是为了确保树能够保持良好的平衡性和高效的操作性能。

红黑树中的叶子结点指的并不是最下面一层的包含关键字的实际的结点,而是指查找失败的结点

红黑树的插入

插入一个新结点看其有没有破坏红黑树的特性,主要是看其有没有违背不红红的特性

数据结构是应用科学不是理论科学,没有所谓的标准答案

红黑树的删除

B树

B树的插入删除

新元素一定是插入到最底层"终端节点",用"查找"来确定插入位置

当左兄弟很宽裕时,用当前结点的前驱、前驱的前驱来填补空缺

B+树

4阶的意思是每个结点最多可以有四颗子树

叶子结点指的是一整块,而不是其中的某一个小方块,一个叶子结点可能会包含m个关键字

一个一个的小方块其实是分别对应了一个关键字

思想和B树是一致的,希望B+树高度尽可能低

可以理解为:要追求"绝对平衡",即所有子树高度要相同

有多路查找和顺序查找两种查找

对于B+树的查找,每查找一层结点的时候其实都需要进行一个读磁盘的操作,直到找到最下面这一层的叶子节点

索引的功能就是通过B+树实现的

散列查找(哈希表)

数组里边只会保存一个指向某个数据元素的指针

散列函数的设计应该尽可能的让不同的关键字可以减少冲突

散列查找是典型的"用空间换时间"的算法,只要散列函数设计的合理,则散列表越长,冲突的概率越低

自我理解就是,有空位的话肯定可以放,没放遇见了空位就说明没有这个数,即查找失败

必须得是逻辑删除,不能是直接删除

Java中的HashMap和HashSet都是用拉链法的方式实现的

困困困

相关推荐
zephyr058 小时前
链表实现O(n log n)时间复杂度的排序——归并排序详解
java·数据结构·算法
XWalnut9 小时前
LeetCode刷题 day37
java·数据结构·算法·leetcode
爱跳舞的烤冷面10 小时前
自学嵌入式第19天(数据结构篇——栈)
数据结构
星轨初途11 小时前
LeetCode 热题 100——day11 滑动窗口最大值
数据结构·c++·算法·leetcode·职场和发展
LuminousCPP1 天前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
白狐_7981 天前
408数据结构第5章:树与二叉树②——遍历、线索树、森林与哈夫曼
数据结构·算法·深度优先
Jasmine_llq1 天前
《P15800 [GESP202603 六级] 选数》
数据结构·long long·逆序线性 dp·从后往前推导·转移严格遵循题意·防止总和溢出·复杂度on
疯狂打码的少年1 天前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
纵有疾風起1 天前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
wuyk5551 天前
1.栈:后进先出的线性数据结构
c语言·数据结构·stm32·单片机