【数据结构】7.2 线性表的查找

news/2024/11/16 6:38:10/

文章目录

  • 7.2.1 顺序查找(线性查找)
    • 顺序查找算法
    • 设置监视哨的顺序查找
    • 顺序查找算法分析
  • 7.2.2 折半查找(二分或对分查找)
    • 折半查找算法
    • 折半查找性能分析 - 判定树
  • 7.2.3 分块查找
    • 分快查找算法
    • 分块查找算法分析及比较
    • 查找方法比较

7.2.1 顺序查找(线性查找)

应用范围

  • 顺序表或线性链表表示的静态查找表
  • 表内元素之间可以无序

数据元素类型定义

  • 数据表可能有多个数据域的值,比如成绩表中有姓名、成绩、总分等。
  • 所以用结构类型来表示要存储的数据元素的类型。
typedef struct
{Keytype key;//关键字域InfoType otherinfo;//其他域}ElemType;

顺序表的定义

//顺序表结构类型定义
typedef struct
{ElemType* R;//存储空间基地址int length;//记录当前表用了多少个数据元素}SSTable;//Sequential Search Table
SSTable St;//定义顺序表 ST

顺序查找算法

顺序查找

  • 在顺序表 ST 中查找值为 key 的数据元素。
  • 例如:查找 13:找到,返回下标 5。查找 60:未找到,返回 NULL。
    • 在此假设元素从 ST.R[1] 开始顺序向后存放,ST.R[0] 闲置不用,
    • 查找时从表的最后开始比较,如下面的算法所示。

在这里插入图片描述

算法描述

//在顺序表 ST 中顺序查找其关键字等于 key 的数据元素。
//若找到,则函数值为该元素在表中的位置(下标),反之返回0.int Search_Seq(SSTable St,KeyType key)
{for(i = St.length;i>=1;i--)//从表的最后开始往前找,i指向数组最后一个元素{if(key == ST.R[i].key){return i;//返回下标}}return 0;//循环完了还没找到说明里面没有要找的元素。
}
  • 这种算法每进行一次循环都要进行两个比较,能否改进?
  • 一次是看看查找的值是不是关键字的值,一次是判断 i 是否越界了。
  • 这种算法用起来稍微麻烦了点,所以这时候就轮到哨兵出击了。

设置监视哨的顺序查找

改进:把待查找关键字 key 存入表头(哨兵监视哨),从后往前逐个比较,可以免去查找过程中每一步都要检查是否检查完毕,加快速度。

  • 假设现在要找的值时 60 ,将要找的值存进0号位置(监视哨)。
  • 在找 60 的时候就不用考虑是否越界了。
  • 一直从后往前找,如果在 0 号位置找到了 60,直接返回下标 0 。也就说明在 1-11号位置没有找到60。

在这里插入图片描述

算法描述

  • 当 ST.length 比较大时,此改进能够使进行一次查找所需要的平均时间几乎减少一半
//在顺序表 ST 中顺序查找其关键字等于 key 的数据元素。
//若找到,则函数值为该元素在表中的下标位置,反之返回0int Search_Seq(SSTable St,KeyType key)
{ST.R[0].key = key;//哨兵,将关键字的值放到下标为0的位置for(i = St.length;ST.R[i] != key;i--); //别忘了 for 后面的分号,忘了就完犊子了return i;
}

顺序查找算法分析

设置监视哨的顺序查找】:时间效率分析

比较次数与 key 的位置有关:

  • 查找第 i 个元素,需要边角 n- i + 1 次。
  • 查找失败时,需要比较 n + 1 次。

在这里插入图片描述

顺序查找的性能分析

  • 时间复杂度O(n)
    • 查找成功时的平均查找长度,设表中各记录查找概率相等。
      在这里插入图片描述
  • 空间复杂度O(1) 需要一个额外的辅助空间(哨兵)。

讨论

  1. 记录的查找概率不相等时如何提高查找效率?
    • 查找表存储记录原则 —— 按查找概率高低存储:
      • 查找概率越高,比较次数越少,放在比较靠后的位置。
      • 查找概率越低,比较次数越多,放在比较靠前的位置。
  2. 记录的查找概率事先不知道时该如何提高查找效率?
    • 方法 —— 按查找概率动态调整记录顺序:
      • 在每个记录中设置一个访问频度域;
      • 始终保持记录按非递增有序的次序排列;
      • 每次查找后均将刚查到的记录直接移动到表头。

顺序查找的特点

  • 优点:算法简单,逻辑次序无要求,且不同存储结构均适用(顺序/链式存储均可)。
  • 缺点:平均查找长度 ASL 太长,时间效率很低。

在这里插入图片描述

7.2.2 折半查找(二分或对分查找)

  • 二分查找:每次将待查记录所在区间缩小一半。只对已经排序的数据有效。

查找过程

在这里插入图片描述
当前数组内的数据元素是按照升序排序的。

  1. 设置一个查找区间初始值,low 指向第一个元素,high 指向最后一个元素。
  2. 当 low <= high 时,循环执行以下操作:
    • 设一个 mid 为 low 和 high 的中间值:mid = (low + high) / 2,当前这个数组的 mid 是 下标 6的元素56。
    • 直接将要找的这个关键字的值 21 和 和中间位置的这个值比较一下,发现 21 < 56,说明这个值一定在 mid 的左边。要将查找范围更新到 mid 左边。
    • 则将新的 high 更新为:key < mid 则:high = mid - 1,因为中间位置也比较过来,不是这家伙。

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

  • 继续拿 mid 的值和 21 比较,发现 19 < 21,说明待查找的值在 mid 的右边,将 low 更新,key > mid 则: low = mid +1
  • 然后再去找中间位置,low是4 high 是5,min的值就是4。

在这里插入图片描述

  • 拿 key 的值 21 和 mid 的值比较,发现 mid = key 则:return mid

如果要找的值不在数组中

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

  • 查找到最后 low 会大于 high 上下限交换了,此时说明数组中没有俺们要找的数。
  • high < low,结束

折半查找算法

非递归算法

  • 设表长为 n ,low、high 和 mid 分别指向待查元素所在区间的上限、下限和中点,令 key 为给定的要查找的值:
  • 初始时,令 low = 1,high = n,mid = (low + high) /2
  • 让 key 与 mid 指向的记录比较:
    • 若 key == R[mid].key,则查找成功。
    • 若 key < R[mid].key,则 high = mid + 1。
    • 若 key > R[mid].key,则 low = mid + 1。
int serch_Bin(SSTable ST,KeyType key)
{low = 1;high = ST.length;//置查找区间初始值while(low <= high){mid = (low + high) / 2;if(ST.R[mid].key == key){return mid;//找到待查找元素}else if(key < St.R[mid].key){high = mid -1;//将查找区间缩小到 mid 左边}else{low = mid + 1;//将查找区间缩到 mid 右边}}return 0;
}

折半查找性能分析 - 判定树

折半查找过程可以用二叉树来描述

  • 树中每一个结点对应表中一个记录,但结点值不是记录的关键字,而是记录在表中的位置序号。
  • 把当前查找区间的中间位置作为根,左子表和右子表分别作为根的左子树和右子树,由此得到的二叉树称为折半查找的判定树
  • 结点所在层数表示该位置的元素需要比较多少次。

在这里插入图片描述

查找成功

  • 比较次数 = 路径上的结点数
  • 比较次数 = 结点所在的层数

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

查找不成功

  • 比较次数 = 路径上的内部结点数
  • 比较次数 <= log₂n + 1。

在这里插入图片描述

  • 假设每个元素的查找概率相等,求查找成功时的平均查找长度。
    • 所有元素的比较次数相加然后除与结点数。

在这里插入图片描述

平均查找长度 ASL(成功时)

  • 设表长 n = 2h -1,则 h = log₂(n+1)(此时,判定树为深度 = h 的满二叉树),且表中每个记录的查找概率相等:Pi = 1/n

在这里插入图片描述

折半查找特点

  • 缺点:效率比顺序查找搞。
  • 缺点:只适用于有序表,且限于顺序存储结构(对线性链表无效)。

7.2.3 分块查找

分块查找:既能使查找效率比较高,又能方便的进行插入和删除。

分快查找算法

  • 一般的字典(图1)俺们是用二分查找的方式来找的,随便翻开一页看到当前单词页的首字母,就知道是该往前还是往后翻了。
  • 而不一般的字典(图2),将所有的单词按照首字母顺序划分成若干块,将这本书分成 26 块区域。
    • 假设要找下面这个单词,直接翻开首字母为 m 的那一块区域,然后在这块区域进行 顺序查找 或者 二分查找。
  • 这种查找方式就称作分块查找,也称索引顺序查找

在这里插入图片描述

分块查找条件

  1. 将表所有元素分成若干块,每一块的内容可以是有序的,也可以是无序的,如果是无序则称作分块有序
    • 分块有序块间有序,块内无序
      • 块之间是有序的,单词是按 A ~ Z这样一个区域块排的,块内可以是无序的。都是字母 m 开头的单词可以随便放(当然字典不能真的随便放)。
    • 定义:若第 i 块在第 j 块之前(i < j),则第 j 块中所有记录的关键字均大于第 i 块中的最大关键字。
      • 如:假设现有一个被分成 3 块的数据表,第一块中的最大值 22 肯定小于第 2、3 块中所有的值。

在这里插入图片描述

  1. 建立索引表(每个结点含有最大关键字域或指向本块第一个结点的指针,且按关键字有序)。
    • 人话:记录每一块区域的最大值,以及每一块是从哪里开始的。

在这里插入图片描述

分快查找过程

  1. 先确定待查找记录(值)在哪块区域(用顺序或折半查找)。
  2. 再在块内查找(用顺序查找)。

举个例子

在这里插入图片描述

  1. 先在索引表中找,第一块区域最大值是 22,那肯定不在第一块,38 < 48,所以在第二块区域找。
  2. 块内元素是无序的,所以就在第二块中进行顺序查找。

分块查找算法分析及比较

分块查找的平均查找次数为:在块之间比较的次数 + 块内查找的次数。

查找效率

在这里插入图片描述

  • 其中:Lb 为查找索引表确定所在块的平均查找长度,Lw 为在块中查找元素的平均查找长度。

在这里插入图片描述

  • 假设总共有 n 个元素,再假设每一块中有 s 个元素,所以索引表就可以分成 n / s 块。
    • 在索引表中的平均查找长度就为:log₂(n / s +1)
    • 在块内进行查找:因为块内是无序的,无序就用顺序查找法,顺序查找的凭据查找长度就是 s / 2

例如:

当 n = 9,s = 3 时

  • 分块法的 ASLbs = 3.5。
  • 折半法的 ASL ≈ log₂n = 3.1。但是折半法需要预先排序,所以任然需要时间。
  • 顺序法的 ASL = (1+n)/2 = 5。

分块查找特点

  • 优点:插入和删除比较容易,无序进行大量移动。
  • 缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算。
  • 适用情况:如果线性表既要快速查找又经常动态变化,则可以采用分块查找。

查找方法比较

在这里插入图片描述


http://www.ppmy.cn/news/19642.html

相关文章

【进击的算法】基础算法——怎么优雅地控制边界范围

学习范围 &#xff1a; ✔️数组 ✔️边界控制本文作者 &#xff1a; 蓝色学者i 边界控制的艺术前言一、为什么需要控制边界&#xff1f;二、怎么优雅地控制边界&#xff1f;三、令人抓狂的二分查找3.1 题目概述3.2解题思路3.3 解决方案方案一&#xff1a;边界都有效方案二&…

Docker 基础 - 3

Web 服务器与应用 Nginx 我的Nginx Docker镜像 ## 设置继承自己创建的 sshd 镜像 FROM caseycui/ubuntu-sshd## 维护者 LABEL maintainer"CaseyCui cuikaidongfoxmail.com"## 安装 nginx RUN apt-get update \&& DEBIAN_FRONTENDnoninteractive apt-get ins…

[Python]调用pytdx的代码示例

安装pytdxpip install pytdx简单示范from pytdx.hq import TdxHq_API api TdxHq_API() # 数据获取接口一般返回list结构&#xff0c; with api.connect(119.147.212.81, 7709): # 返回普通listdata api.get_security_bars(9, 0, 000001, 0, 10) print(data)输出结果[Ordered…

什么是YOLOR?

简述YOLOR 是一种用于对象检测的最先进的机器学习算法&#xff0c;与 YOLOv1-YOLOv5 不同&#xff0c;原因在于作者身份、架构和模型基础设施的差异。YOLOR 代表“你只学习一种表示”&#xff0c;不要与 YOLO 版本 1 到 4 混淆&#xff0c;其中 YOLO 代表“你只看一次”。 YOLO…

深度卷积对抗神经网络 基础 第四部分 可控制的GANs(Controllable GANs)

不同的生成模型定义 深度卷积对抗神经网络包含两种不同的生成模型&#xff0c; 条件生成模型 和非条件生成模型。非条件生成模型就像是一个彩票机或者赌博机&#xff0c;你输入一个任意数字的硬币数量&#xff0c;而输出则是随机的彩球。这样的系统&#xff0c;我们不能控制输…

Leetcode:491. 递增子序列(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 回溯&#xff1a; 原理思路&#xff1a; 优化版&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至…

3000字英文随笔(挽救下语感)

&#x1f33c;遥远的她(吉他版) - 張子铭 - 单曲 - 网易云音乐 &#x1f33c;New Boy - 房东的猫/陈婧霏 - 单曲 - 网易云音乐 实际只有800个单词哈 我会借助有道词典&#xff0c;百度翻译 结合所剩不多的语感&#xff0c;尽己所能地道地表达 杜绝中式英语&#xff0c;当…

RK3399平台开发系列讲解(文件系统篇)文件回写过程介绍

🚀返回专栏总目录 文章目录 一、编程接口二、回写过程2.1、周期回写2.2、强制回写2.3、系统调用sync沉淀、分享、成长,让自己和他人都能有所收获!😄 📢进程写文件时,内核的文件系统模块把数据写到文件的页缓存,没有立即写回到存储设备。文件系统模块会定期把脏页(即…