866数据结构笔记 - 第七章 查找

 湖大计学考研系列文章目录

  • 22湖南大学计算机学硕上岸经验
  • 22湖南大学 866 数据结构真题(回忆版)
  • 866数据结构重点内容
  • 866 数据结构模拟题(一)及解析
  • 866数据结构笔记 - 第一章 绪论
  • 866数据结构笔记 - 第二章 线性表
  • 866数据结构笔记 - 第三章 栈和队列
  • 866数据结构笔记 - 第四章 串
  • 866数据结构笔记 - 第五章 树和二叉树
  • 866数据结构笔记 - 第六章 图 
  • 866数据结构笔记 - 第七章 查找
  • 866数据结构笔记 - 第八章 排序 

目录

重点内容

一、基本概念

二、顺序查找(线性查找)

1. 算法实现

2. 优化

三、折半查找

四、分块查找

五、B树(B-树)

六、散列查找

1. 基本概念

2. 散列函数

3. 解决冲突的办法

4. 散列查找及性能分析

七、自组织线性表

参考(具体细节见原文)


重点内容

        22年866真题:2个选择+1个计算,共计14分

  1. 折半查找以及折半查找树
  2. 散列查找(线性探测法、平方探测法)(必考大题)
  3. 自组织线性表三种规则(期末题里面会出现,但是感觉出大题的可能性不大,选择题有可能)

一、基本概念

  • 查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找。
  • 查找表(查找结构):用于查找的数据集合称为查找表,它由同⼀类型的数据元素(或记录)组成。
  • 关键字:数据元素中唯⼀标识该元素的某个数据项的值,使⽤基于关键字的查找,查找结果应该是唯⼀的。
  • 查找长度:在查找运算中,需要对比关键字的次数称为查找长度。
  • 平均查找长度(ASL):所有查找过程中进行关键字的比较次数的平均值。数量级反映了查找算法的时间复杂度。

866数据结构笔记 - 第七章 查找_第1张图片

二、顺序查找(线性查找)

1. 算法实现

        从头到尾挨个找(或者从尾到头)。

typedef struct{				//查找表的数据结构(顺序表)
    ElemType *elem;			//动态数组基址
    int TableLen;			//表的长度
}SSTable;

//顺序查找
int Search_Seq(SSTable ST,ElemType key){
    int i;
    for(i=0;i

2. 优化

        有序表

866数据结构笔记 - 第七章 查找_第2张图片

        各个关键字被查找概率不同 

866数据结构笔记 - 第七章 查找_第3张图片

三、折半查找

  • 适用范围:只适用于有序顺序表。
  1. 在【low,high】之间查找目标关键字,每次mid=(low+high)/2
  2. 根据mid所指元素与目标关键字大小调整low和high
  3. 不断缩小low和high范围,若low>high,则查找失败。
  • 折半查找判定树的构造: mid = [(low + high)/2],如果当前low和high之间有奇数个元素,则mid分隔后,左右两部分元素个数相等,如果当前low和high之间有偶数个元素,则mid分隔后,左半部分比右半部分少1个元素。
  • 折半查找的判定树中,若mid = [(low + high)/2],则对于任何一个结点,右子树结点数 - 子树结点数 = 0 或 1。
  • 折半查找的判定树一定是平衡二叉树。折半查找的判定树中,只有最下面一层是不满的。因此,元素个数为n时树高h =[log2(n +1)]。
  • 判定树结点关键字:左<中<右,满足二叉排序树的定义。
  • 失败结点: n+1个(等于成功结点的空链域数量)
  • 折半查找的查找效率:折半查找的时间复杂度=O(log2n)。
typedef struct{
    ElemType *elem;
    int TableLen;
}SSTable;

// 折半查找
int Binary_Search(SSTable L,ElemType key){
    int low=0,high=L.TableLen,mid;
    while(low<=high){
        mid=(low+high)/2;
        if(L.elem[mid]==key)
            return mid;
        else if(L.elem[mid]>key)
            high=mid-1;					//从前半部分继续查找
        else
            low=mid+1;					//从后半部分继续查找
    }
    return -1;
}

四、分块查找

  • 分块查找所针对的情况:块内无序、块间有序
  • 算法思想:索引表中记录每个分块的最大关键字,分块区间,先查索引表(顺序或折半)再对分块进行顺序查找。
  • 查找目标关键字所在分块可使用顺序查找和折半查找两种方式。
  • 若使用折半查找且索引表中不包含目标关键字,则最终要停在low > high,要在low所指分块中查找目标关键字。
  • 查找效率分析(ASL)︰假设长度为n的查找表被均匀地分为b块,每块s个元素。设索引查找和块内查找的平均查找长度分别为L、Ls,则分块查找的平均查找长度为: ASL=L+Ls。

五、B树(B-树)

  • B树,又称多路平衡查找树,B树中所有结点的孩子个数的最⼤值称为B树的阶,通常用m表示。⼀棵m阶B树或为空树,或为满足如下特性的m叉树:
    • 树中每个结点至多有 m 棵子树,即至多含有 m-1 个关键字。
    • 若根结点不是终端结点,则⾄少有两棵子树。

866数据结构笔记 - 第七章 查找_第4张图片

1.B树的查找:B树的查找操作与二叉查找树类似。B树的查找包含两个基本操作:

  • 在B树中找结点
  • 在结点中找关键字。B树常存储在磁盘上,因此前一个查找操作在磁盘上进行,后一个查找操作在内存中进行。在B树中查找到某个结点后,先在有序表中进行查找,若找到则查找成功,否则按照对应指针信息到所指的子树中去查找.查找到叶子结点(对应指针为空指针),则说明树中没有对应的关键字,查找失败。

2.B树的插入:将关键字key插入到B树的过程:

  • 定位:利用B树的查找算法,找到插入该关键字的最底层中的杲个非叶子结点。(插入位置一定是最底层的某个非叶子结点)
  • 插入:B树中,每个非失败节点的关键字个数都在区间[[m/2]- 1,m -1]内。若插入关键字key之后结点关键字个数小于m,则可以直接插入;否则必须对结点进行分裂。
  • 分裂:从结点的中间位置([m/2|)将其中的关键字分为两部分,左半部分包含的关键字放到原结点中,右半部分包含的关键字放到新节点中,中间位置([m/2])的关键字则插入原节点的父节点。若此时父节点的关键字也超过了上限,则对父节点继续进行分裂操作,直到这个过程传到根节点为止,进而导致B树的高度增加。

3.B树的删除:

  • 非终端结点的删除:使用直接前驱或者直接后继来代替被删除的关键字,转换为删除终端结点。
  • 终端结点的删除,具体分为三种情况:
    • 直接删除关键字:若删除关键字所在结点关键字个数 ≥m/2,则可直接删除。
    • 兄弟够借:若删除关键字所在结点关键字个数=[m/2]-1,且与此结点相邻的左(或右〉兄弟结点关键字个数≥[m/2],则需调整该节点、左(或右)兄弟结点及其双亲结点(父子换位法)以达到新的平衡。
    • 兄弟不够借︰若删除关键字所在结点关键字个数=[m/2]-1,且与此结点相邻的左(或右〉兄弟结点关键字个数= [m/2] -1,则将该节点、左(或右)兄弟结点及其双亲结点中的关键字进行合并。

4.一棵m阶的B+树需满足以下条件:

  • 每个分支节点最多有m棵子树(孩子结点)。
  • 非叶根结点至少有两颗子树,其他每个分支结点至少有⌈ m / 2 ⌉ ⌈m/2⌉⌈m/2⌉棵子树。
    结点的子树个数与关键字个数相同。
  • 所有叶子结点包含所有关键字及指向相应记录的指针,叶子结点中将关键字按大小排列,并且相邻叶子结点按大小顺序相互链接起来。(说明B+树支持顺序查找)
  • 所有分支节点仅包含它的各个节点中关键字的最大值及指向其子节点的指针。

866数据结构笔记 - 第七章 查找_第5张图片

六、散列查找

1. 基本概念

  • 散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记作Hash(key)= addr。
  • 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突。发生碰撞的不同关键字称为同义词。
  • 散列表:根据关键字而直接进行访问的数据结构。散列表建立了关键字和存储地址之间的一种直接映射关系。
  • 装填因子:一般计为 α ,即一个表的装满程度,α =表中记录数/表长。

2. 散列函数

  • 直接定址法:直接取关键字的某个线性函数值为散列地址,散列函数为H(key)= key或H(key)= a x key+b。这种方法计算简单,不会产生冲突。缺点是空位较多,会造成存储空间浪费。
  • 除留余数法:假定散列表表长m,取一个不大于但最接近m的质数p,利用散列函数H(key) = key%p将关键字转换为散列地址。p取质数是因为这样可以使关键字通过散列函数转换后等概率地映射到散列空间上的任一地址。
  • 数字分析法:假设关键字是 r进制数,而r个数码在个位上出现的频率不一定相同,可能在某些位上分布而在某些位分布的不均匀。此时应选数码分布均匀的若干位作为散列地址。
  • 平方取中法:这种方法取关键字平方值的中间几位作为散列地址,具体取多少位视具体情况而定。这种方法得到的散列地址与关键字的每一位都有关系,因此使得散列地址分布比较均匀。适用于关键字每位取值都不够均匀或均小于散列地址所需的位数。

3. 解决冲突的办法

1.开放定址法:指可存放新表项的空闲抵制既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为:H=(H (key)+ di)%m其中,H(key)为散列函数,i=0,1,2.k(k

  • 线性探测法:d=0,1,2...,.m -1。使用方法发生冲突时,顺序查看下一个单元,直到找到一个空闲单元或查遍全表。使用这种方法可能造成大量元素在相邻的散列地址上堆积起来,大大降低了查找效率。使用这种方法删除元素时需要做标记,否则会影响查找元素。
  • 平方探测法:d =02,12,_12, 2,_2... k2,一k2。其中k ≤m/2,散列表长度m必须是一个可以表示为4k+3的质数(符合这个条件才能够探测到所有位置)。使用这种方法可以避免堆积问题。
  • 再散列法:d = H(key)。当通过第一个散列函数H(key)得到的地址发生冲突时,则利用第二个散列函数Ho(key)再次计算该关键字的地址。其散列函数为:H=RH(key)。
  • 伪随机序列法:d=伪随机序列。

2.拉链法:对于不同的关键字通过散列函数映射到同一地址时,为了与避免非同义词发生冲突,可以把所有的同义词存储到一个线性链表中。拉链法适用于经常进行插入和删除的方法。

4. 散列查找及性能分析

1.散列查找执行步骤如下:

  • 1.初始化: Addr = Hash(key)
  • 2.检测查找表中地址为Addr的位置上是否有记录,若无记录,返回查找失败;若有记录,比较它和key的值,若相等则返回查找成功,否则执行步骤③。
  • 3.用给定的处理冲突方式计算“下一个散列表地址”,并把Addr置为此地址,转入步骤②。

2.平均查找长度(ASL)︰散列表查找成功的平均查找长度即找到表中已有表项的平均比较次数;散列表查找失败的平均查找长度即找不到待查的表项但能找到插入位置的平均比较次数。

七、自组织线性表

        线性表在大多数情况下根据关键码值进行排序,再进行检索。但是我们也可以不通过排序,而是估算记录被访问的频率更改记录在线性表中的位置。

  • 计数方法:类似于LFU(最不经常使用),每当访问一条记录时,若这条记录的访问数大于排在它前面的记录的访问数,这条记录就会在线性表中向前移动。缺点:一旦一条记录被访问了很多次,不管将来的访问历史如何,它都会一直在线性表的前面。
  • 移至前端:类似于LRU(最近最少使用),若找到一条记录,就把它放在线性表的最前面。移至前端方法对访问频率的局部变化能很好地反应,因为当一条记录在一段时间内被频繁访问时,那么在这段时间它会靠近线性表的前端。
  • 转置方法:若找到一条记录,则把这条记录与它在线性表中的前一条记录交换位置。

        假定有八条记录,其关键码值为从A到H,并且最初的排列顺序为:A,B,C,D,E,F,G,H(字母顺序)。当按照下面的字符流对这八条记录进行访问时,上面三种不同的启发式方法分别需要进行多少次比较。F D F G E G F A D F G E

按照计数方法:

第一次:F1 A0 B0 C0 D0 E0 G0 H0
第二次:F1 D1 A0 B0 C0 E0 G0 H0
第三次:F2 D1 A0 B0 C0 E0 G0 H0
第四次:F2 D1 G1 A0 B0 C0 E0 H0
第五次:F2 D1 G1 E1 A0 B0 C0 H0
第六次:F2 G2 D1 E1 A0 B0 C0 H0
第七次:F3 G2 D1 E1 A0 B0 C0 H0
第八次:F3 G2 D1 E1 A1 B0 C0 H0
第九次:F3 G2 D2 E1 A1 B0 C0 H0
第十次:F4 G2 D2 E1 A1 B0 C0 H0
第十一次:F4 G3 D2 E1 A1 B0 C0 H0
第十二次:F4 G3 D2 E2 A1 B0 C0 H0
最后线性表中的记录顺序为:F G D E A B C H
需要比较的次数为:6+5+1+7+7+3+1+5+3+1+2+4=45

按照移至前端方法:

第一次:F A B C D E G H
第二次:D F A B C E G H
第三次:F D A B C E G H
第四次:G F D A B C E H
第五次:E G F D A B C H
第六次:G E F D A B C H
第七次:F G E D A B C H
第八次:A F G E D B C H
第九次:D A F G E B C H
第十次:F D A G E B C H
第十一次:G F D A E B C H
第十二次:E G F D A B C H
最后线性表中的记录顺序为:E G F D A B C H
需要比较的次数为:6+5+2+7+7+2+3+5+5+3+4+5=54

按照转置启发式规则:

第一次:A B C D F E G H
第二次:A B D C F E G H
第三次:A B D F C E G H
第四次:A B D F C G E H
第五次:A B D F C E G H
第六次:A B D F C G E H
第七次:A B F D C G E H
第八次:A B F D C G E H
第九次:A B D F C G E H
第十次:A B F D C G E H
第十一次:A B F D G C E H
第十二次:A B F D G E C H
最后线性表中的记录顺序为:A B F D G E C H
需要比较的次数为:6+4+5+7+7+7+4+1+4+4+6+7=62


参考(具体细节见原文)

参考书目:

  1. 王道:《数据结构》
  2. 湖大本科: 《数据结构与算法分析( C++版)(第三版)》Clifford A. Shaffer 著,张铭、刘晓丹等译

  3. 数据结构学习笔记(王道)_梦入_凡尘的博客-CSDN博客_王道数据结构笔记

  4. No42.检索--自组织线性表 - 简书 (jianshu.com)

你可能感兴趣的:(考研,数据结构,经验分享,哈希算法)