数据结构 第7章总结

查找

  查找

   在数据结构中寻找满足某种条件的数据元素的过程

   查找表:用于查找的数据集合,由同一种数据类型(或记录)组成,可以是一个数组或链表等数据类型

   操作:查询、检索、插入、删除(只有前两种的称为静态查找表、包含后两种的称为动态查找表)

   关键字:数据元素中唯一标识该元素的某个数据项的值

   平均查找长度(ASL):查找时,关键字比较次数的平均值

    顺序查找

      线性查找,主要用于在线性表(顺序存储、链式存储)中进行查找(有序无序皆可)

      无序线性表进行顺序查找,查找失败时要遍历整个线性表

        tips:将数组零号下标的位置赋值为key,免去判断表尾(头)的语句(但不是所有的情况都用)

        ASL=(n+1)/2(成功),ASL=n+1(失败,有哨兵的情况下)

      有序线性表进行顺序查找,查找失败时不一定要遍历整个线性表

        判定树:所有左子树的值都比根结点要小,所有右子树的值都比根结点要大。查找key时,key小于根节点往其左子树查找,大于根结点往其右子树查找

    折半查找

      二分查找,仅适用于有序的顺序表(且要求序列一定有序)

      算法思想

        首先将给定值key与表中中间位置元素的关键字比较

        若相等,则返回该元素的位置

        若不等,则在前半部分或是后半部分进行查找

        查找序列升序时,

        若key小于中间元素,则查找前半部分

        若key大于中间元素,则查找后半部分 

        重复该过程,直至查找到元素或查找失败为止

      查找的比较次数与二叉树的层数相关,折半查找的二叉树更趋向于平衡二叉树,所以查找效率更高(较线性查找)

      ASL=log2 (n+1)  -1(成功) 时间复杂度 O(log2 n)

    分块查找

      索引顺序查找,既有动态结构,又适用于快速查找

      如何分块

        将查找表分为若干子块,块内元素可以无序,块间有序,对于所有块有第i块的最大关键字小于第i+1块的所有记录的关键字

        建立索引表,索引表中的每个元素含有各块的最大关键字和各块中的第一个元素的地址,索引表按关键字有序排列

      如何查找

        确定所在块:顺序查找/折半查找

        块内查找:顺序查找

    B-树

      多路平衡查找树

      一棵m阶B-树(非空)

      1)树中的每个结点至多有m棵子树(即至多含有m-1个关键字)

      2)若根节点不是终端结点,则至少有两棵子树

      3)除根结点外的所有非叶结点至少有[m/2](取上界)棵子树(即[m/2](取上界)-1个关键字)

    B+树

      (较B-树)所有叶结点包含全部关键字及只想相应记录的指针,叶结点中将关键字按大小顺序排列,并且相邻节点按大小顺序连接起来

    散列表

      根据关键字而直接进行访问的数据结构。建立了关键字与存储地址之间的一种直接映射关系

      散列函数:把查找表中的关键字映射成该关键字对应的的

        Hash(key)=address

        1)定义域必须包含全部需要存储的关键字,至于的范围依赖于散列表的大小或地址范围

        2)计算出来的地址应等概率、均匀分布在整个地址空间中,从而减少冲突的发生

        3)尽量简单,能在较短时间内计算出任一关键字对应的散列地址

        构造方法:数字分析法、平方取中法、折叠法、除留余数法(取一个不大于表长但最接近或等于表长的质数p,Hash(key)=key%p)

      冲突:散列函数可能会把多个不同的关键字映射到同一地址下的情况

        处理方法

          开放地址法:可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放(不能随便删除某个元素

            计算增量序列:线性探测法(0、1、2、3...)、二次探测法(0、1、-1、2^2、-2^2…)、伪随机探测法

          链地址法

            把所有同义词存放在一个线性链表中,这个线性链表由地址唯一标识,即散列表中每个单元存放该链表头指针(适用于经常进行插入和删除的情况)

          查找效率

            装填因子:α=表中记录数n/散列表长度m

            散列表的平均查找长度依赖于散列表的装填因子

————————————————————

6.15讨论二

1.      当key存在时,通过例子来说明

        (1)     设有序表a={2,3,4,5},key=4

        初始化:low=1,high=a.length=4

        第一次循环:mid=(low+high)/2=2(mid一定为整型,会向下取整)

                               此时key>a.R[2].key(4>3),low=mid+1=2,退出本次循环

        第二次循环:mid=(low+high)/2=3

                               此时key=a.R[3].key(4=4),返回2后退出函数

   

  在(1)中,循环只对low和mid进行更新,不涉及更改的部分,查找可以正常进行;所以当key存在时,查找正常进行

2.      当key不存在时,通过例子来说明

        (1)     设有序表a={3,3},key=2

        初始化:low=1;high=a.length=2

        第一次循环:mid=(low+high)/2=1(mid一定为整型,会向下取整)

                              此时key<a.R[1].key(2<3),high=mid=1,退出本次循环

        第二次循环:mid=(low+high)/2=1,

                              此时key<a.R[1].key(2<3),high=mid=1,退出本次循环

                               ……

        随着程序运行,high=mid=low,进入死循环

        (2)     设有序表a={2,2},key=3

        初始化:low=1,high=a.length=2

        第一次循环:mid=(low+high)/2=1(mid一定为整型,会向下取整)

                   此时key>a.R[1].key(3>2),low=mid+1=2,退出本次循环

        第二次循环:mid= mid=(low+high)/2=2,

                   此时key> a.R[2].key(3>2),low=mid+1=3,退出本次循环

        第三次:在while判断处,low>high(3>2),未进入循环,返回0后退出函数

       在(2)中,key大于有序表中的所有值,只对low和mid进行更新,故程序正常运行

       在(1)中,key小于有序表中的所有值,循环只会对high和mid进行更新,且此时对high的更新为high=mid,最终会使得high=mid=low,进入死循环

————————————————————

总结:本章学习下来明显比前一章要轻松,内容简单了不少而且很多都是之前接触过的知识,但是在细节部分依旧非常重要,比如说折半查找法中low和high的取值,在讨论二中将high=mid-1改为high=mid时,若key不存在且小于表中所有值就会出现死循环的情况,这里需要自己比对过后才能深入了解。本章我认为最重要的部分就是散列表(Hash表),可以很大地提升查找的效率。几种处理冲突的方式(特别是线性探测法)需要熟悉运作方式,自己多手动跑几遍就清楚了,个人小测的时候就是因为没有搞清楚所以反反复复改了好几回,最后可能还是错了,等晓梅老师下次课讲的时候好好听一下。呜呜呜要期末了感觉很多知识还不是很清楚好慌张啊,赶紧放弃幻想认清现实,好好复习,特别是链表部分!要熟悉逻辑和操作!不要蒙擦擦!

猜你喜欢

转载自www.cnblogs.com/cmlearning/p/13200469.html