查找—简洁版

查找

查找的基本概念

1、查找的定义

在这里插入图片描述

  • “查找表” :同一类型的数据元素(或记录)构成的集合。 由于“集合”中的数据元素之间存在松散的关系,可用查找表进行灵活应用;

查找—指根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素;

  • 若表中存在这样的一个记录, 则称查找成功,查找的结果可给出整个记录的信息,或指 示该记录在查找表中的位置;
  • 若表中不存在关键字等于给定值的记录,则称查找不成功,此时查找的结果可给出一个 “空” 记录或 “空” 指针;

2、查找表的分类和评价指标

  • 分类

静态查找表 仅作“查询”(检索)操作的查询表;

动态查询表 作“插入”和“删除”操作的查询表;

  • 查找算法的评价指标

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

在这里插入图片描述

线性表的查找

1、顺序查找

  • 应用范围:

​ 顺序表或线性链表表示的静态查找表

​ 表内元素之间无序;

  • 顺序表的表示:
typedef struct {

    ElemType *R;//表基址   

    int length;//表长 

}SSTable;
  • 在顺序表中查找值为e的数据元素
int LocateELem(SqList L,ElemType e){ 

    for (i=0;i< L.length;i++)

        if (L.elem[i]==e) return i+1;                

    return 0;

}

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

  • 在顺序表ST中查找值为Key的数据元素 查找13:找到,返回下标5;如果没找到返回0;
int Search_Seq( SSTable ST , KeyType key ){

    ST.R[0].key =key;		//若成功返回其位置信息,否则返回0

    for( i=ST.length; ST.R[ i ].key!=key;  -- i );//不用for(i= ST.length-1; i>0; --i) 或 for(i=1; i< ST.length; i++) 

        return i; 

}

空间复杂度:一个辅助空间—O(1);

时间复杂度:

1、查找成功时的平均查找长度:ASLs(n)=(1+2+ … +n)/n =(n+1)/2;

2、查找不成功时的平均查找长度:ASLf =n+1;

  • 优点:算法简单,逻辑次序无要求,适用于不同的存储结构;

  • 缺点:ASL太长,时间效率太低;

  • 改进措施:非等概率查找时,可按照查找概率进行排序。

2、折半查找

  • 也称二分查找:首先使用排序算法对查找表进行排序,保证有序;
  • 以升序数列为例,比较一个元素与数列中的中间位置的元素的大小: 如果比中间位置的元素大,则在后半部分的数列进行二分查找 如果比中间位置的元素小,则在前半部分数列的进行二分查找 如果相等,找到了元素的位置。

在这里插入图片描述

若k==R[mid].key,查找成功;

若k<R[mid].key,则high=mid-1;

若k>R[mid].key,则low=mid+1;

在这里插入图片描述

在这里插入图片描述

设表长为n,low、high和mid分别指向待查元素所在区间的上界、下界和中点,k为给定值;

初始时,令low=1,high=n,mid= (low+high)/2

让k与mid指向的记录比较

若k==R[mid].key,查找成功;

若k<R[mid].key,则high=mid-1;

若k>R[mid].key,则low=mid+1;

重复上述操作,直至low>high时,查找失败

int BinSearch(int r[],int low,int high,int k){

    int mid;

    if(low>high) return 0;

    else{

        mid=(low+high)/2;

        if(k<r[mid]) return BinSearch(r,low,mid-1,k);

        else if(k>r[mid]) return BinSearch(r,mid+1,high,k);

        else return mid;

    }
}

int BinSearch(int r[],int n,int k){

    int mid,low=1,high=n;

    while(low<=high){

        mid=(low+high)/2;

        if(k<r[mid]) high=mid-1;

        else if(k>r[mid])

            low=mid+1;

        else

            return mid;

}

    return 0;		//查找失败返回0

}

在这里插入图片描述

假定每个元素的查找概率相等,求查找成功时的平均查找长度。

在这里插入图片描述

ASL=(1x1+2x2+4x3+4x4 ) x1/11=33/11=3;

查找过程

每次将待查记录所在区间缩小一半,比顺序查找效率高,时间复杂度O(log2n);

适用条件

采用顺序存储结构的有序表,不宜用于链式结构;

3、分块查找

分块有序,即分成若干子表,要求每个子表中的数值都比后一块中数值小(但子表内部未必有序);

然后将各子表中的最大关键字构成一个索引表,表中还要包含每个子表的起始地址(即头指针);

在这里插入图片描述

分块查找的平均查找长度为索引查找和块内查找的平均长度之和。设长度为n 的查找表均匀地分 为b 块,每块有s 个记录,在概率相等的情况下,如果对索引表进行顺序查找,则

在这里插入图片描述

如果对索引表进行折半查找,则
在这里插入图片描述

  • 优点:插入和删除比较容易,无需进行大量移动;

  • 缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算;

  • 适用情况:如果线性表既要快速查找又经常动态变化,则可采用分块查找。

就平均查找长度而言,折半查找的平均查找长度最小,分块查找次之,顺序查找最大;

就表的结构而言,顺序查找对有序表、无序表均适用,折半查找仅适用于有序表,而分块查找要求表中元素至少是分块有序的。

在这里插入图片描述

二叉排序树

在这里插入图片描述

1、二叉排序树的定义

二叉排序树(Binary Sort Tree, BST),也称二叉查找树;

二叉排序树或者是一棵空树,或者是一棵具有下列特性的非空二叉树:

1、 若左子树非空,则左子树上所有结点关键字均小于根结点的关键字值;

2、 若右子树非空,则右子树上所有结点关键字均大于根结点的关键字值;

3、 左、右子树本身也分别是一棵二叉排序树。

二叉排序树是一个递归的数据结构 根据二叉树的定义,可得左子树结点值 < 根结点值 < 右子树结点值。 所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。

2、二叉排序树(BST)的操作

  • 创建

在这里插入图片描述

将8作为根节点

插入3,由于3小于8,作为8的左子树

插入10,由于10大于8,作为8的右子树

插入1,由于1小于8,进入左子树3,1又小于3,则1为3的左子树

插入6,由于6小于8,进入左子树3,6又大于3,则6为3的右子树

插入14,由于14大于8,进入右子树10,14又大于10,则14为10的右子树

插入4,由于4小于8,进入左子树3,4又大于3,进入右子树6,4还小于6,则4为6的左子树

插入7

插入13

在这里插入图片描述

  • 查找
bool search(Node* root, int key){ 

    while (root != NULL){

        if(key == root->data)  

            return true;  

        else if(key < root->data) 

            root = root->left;  

        else   

            root = root->right; 

    } 

    return false;

}

在这里插入图片描述

  • 删除

1、被删除结点为叶子结点

直接从二叉排序中删除即可,不会影响到其他结点。例如删去7:

在这里插入图片描述

2、被删除结点D仅有一个孩子 如果只有左孩子,没有右孩子,那么只需要把要删除结点的 左孩子连接到要删除结点的父亲结点,然后删除D结点;

如果只有右孩子,没有左孩子,那么只要将要删除结点D的 右孩子连接到要删除结点D的父亲结点,然后删除D结点;

在这里插入图片描述

3、被删除结点左右孩子都在

在这里插入图片描述

保证删除结点8后,再次中序遍历它,仍不改变其升 序的排列方式。 只有用7或者10来替换8原来的位置。

在这里插入图片描述

平均查找长度和二叉树的形态有关:

最好:log2n(形态匀称,与二分查找的判定树相似);

最坏:(n+1)/2(单支树);

第i层结点需比较i次,两图的平均查找长度为:

在这里插入图片描述

在这里插入图片描述

平衡二叉树

1、平衡二叉树(AVL)的定义

  • 平衡二叉树(AVL):任意节点的子树的高度差都小于等于1的二叉排序树;

在这里插入图片描述

平衡因子 BF( Balance Factor ):左子树和右子树高度差 一般来说 BF 的绝对值大于 1,平衡树二叉树就失衡,需要「旋转」纠正 最小不平衡子树是距离插入节点最近的,并且 BF 的绝对值大于 1 的节点为根节点的子树。 旋转纠正只需要纠正最小不平衡子树即可;

不论用什么方法,操作以后,都是让是三个点之中大小为中间的数做根,比中间 数小的数,做根的左孩子,比中间数大的数,做根的右孩子,因此有一个简单的 方法:

1、不管什么结构,从最深的叶子节点向上递归查找第一个失衡的点,标号为1;

2、再选1下面的点为2;

3、再选2下面的点为3;

4、不管什么结构,大小为中间的数做根,比中间数小的数,做根的左孩子,比中 间数大的数,做根的右孩子;

5、然后按照分支和每个点之间的关系,补全,这样就完成了。

2、平衡二叉树(AVL)的操作

  • 将下面序列构成一棵平衡二叉排序树( 13,24,37,90,53)

在这里插入图片描述

B树与B+树

1、B树的定义

  • B树即为B-树。因为B树的原英文名称为B-tree(Balance-Tree);

    比如数据库里有一张表,有100万条记录,现在要查找其中的某条数据,如何快速地从100万条 记录中找到需要的那条记录呢?

    在这里插入图片描述

  • 平衡:所有叶子结点在同一层,左边和右边分布均匀;

  • 有序:每个结点中有序,且左子树小于根,根小于右子树;

  • 多路:多棵子树(如果最多子树个数为m,则称m阶B-tree )。

在这里插入图片描述

  • 所有叶子结点都在同一层上(失败结点,指向叶子的指针为空);
  • 结点中按关键字大小顺序排列,非叶子结点的结构如下:n为关键字,p为指针

在这里插入图片描述

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

(2)若根节点不是终端结点,则至少有两棵子树。 当根节点为叶子节点时,可以没有子树;不为叶子节点时,至少有一个关键字,也就是至少有两 棵子树;

(3)除根节点外的所有非叶结点至少有ceil(m/2)棵子树,即至少含有ceil(m/2)-1个关键字。 (为了减少不必要的层高,提高效率和资源利用率) ceil(x)函数用于求不小于 x 的最小整数,也即向上取整。

2、B树的查找

在这里插入图片描述

3、B树的插入

插入后确保至多m-1个关键字;

先查找,进入最下层结点;

​ 有空位,直接插入;

该结点中关键字个数n<m-1,有序插入到该结点的合适位置;

​ 无空位,分裂;

即原关键字个数n=m-1 。

在这里插入图片描述

在这里插入图片描述

无空位,插入85

在这里插入图片描述

无空位,插入7

在这里插入图片描述

4、B树的删除

删除后的结点中的关键字个数>= ceil(m/2)-1,因此将涉及结点的“合并”问题。由于删除的关键字位 置不同,可以分为关键字在终端结点和不在终端结点两种情况。 首先找到待删关键字key所在结点 (1)若key在最下层结点中

结点中关键字个数 > m/2-1, 则直接删除

结点中关键字个数== m/2-1, 且兄弟… > m/2-1,则借调

结点、其兄弟的关键字个数都== m/2-1,则合并

(2)若key不在最下层,为了“中序有序”

用key的左子树中的最大码或右子树中的最小码k取代key,然后从该子树中删除k(k一定在最下层)

在这里插入图片描述

删除关键字K=50

在这里插入图片描述

删除关键字K=53

在这里插入图片描述

在这里插入图片描述

首先找到待删关键字key所在结点

(1)若key在最下层结点中

结点中关键字个数 > m/2-1, 则直接删除;

结点中关键字个数==m/2-1, 且兄弟… > m/2-1,则借调;

结点、其兄弟的关键字个数都==m/2-1,则合并;

(2)若key不在最下层,为了“中序有序”

用key的左子树中的最大码或右子树中的最小码k取代key,然后从该子树中删除k(k一定在 最下层)

在这里插入图片描述

在这里插入图片描述

5、B+树

B+树是数据库和操作系统中的一种用于文件查找的数据结构,是一种高效的平衡查找树(效率比B-树高)

在这里插入图片描述

在B+树中,具有n个关键字的结点只含有n棵子树,即每个关键字对应一棵子树。叶结点包含了全部关键字,即在非叶结点中出现的关键字也会出现在叶结点中,且叶结点的指针指向记录。在B-树中,具有n个关键字的结点含有(n+1)棵子树,叶结点和其他结点包含的关键字是不重复的。

在这里插入图片描述

在B+树中,叶结点包含信息,所有非叶结点仅起到索引作用,非叶结点中的每个索引项只含有对应子树 的最大(或最小)关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。

在B-树中每个关键字对应一个记录的存储地址;

在B+树中,有一个指针指向关键字最小的叶子结点,所有叶子结点链接成一个单链表。

  • B+树比B-树更适合实际应用中操作系统的文件索引

在这里插入图片描述

红黑树

1、红黑树的性质

平衡二叉树最大的作用就是查找,AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。 但是,插入节点之后,为了让它重新维持在一个平衡状态,就需要对其进行旋转处理, 那么创建 一颗平衡二叉树的成本其实不小;

红黑树是一种自平衡的二叉查找树,是一种高效的查找树。可在 O(logN) 时间内完成查找、 增加、删除等操作;

红黑树是一种接近平衡的二叉树(说它是接近平衡因为它并没有像AVL树的平衡因子的概念, 它只是靠着满足红黑节点的5条性质来维持一种接近平衡的结构,进而提升整体的性能,并 没有严格的卡定某个平衡因子来维持绝对平衡);

通过任意一条从根到叶子简单路径上颜色的约束,红黑树保证最长路径不超过最短路径的二 倍,因而近似平衡(最短路径就是全黑节点,最长路径就是一个红节点一个黑节点,当从根 节点到叶子节点的路径上黑色节点相同时,最长路径刚好是最短路径的两倍)。

  • 红黑树的性质

节点是红色或黑色;

根是黑色;

叶子节点(外部节点,空节点)都是黑色,这里的叶子节点指的是最底层的空节点(外部节点), 红色节点的子节点都是黑色,红色节点的父节点都是黑色,从根节点到叶子节点的所有路径上不 能有 2 个连续的红色节点;

从任一节点到叶子节点的所有路径都包含相同数目的黑色节点。

2、红黑树的插入

在这里插入图片描述

并查集

1、并查集的定义

在这里插入图片描述

用集合中的某个元素来代表这个集合,则该元素称为此集合的代表元。

2、并查集的操作

定义一个数组:int fa[1000]; (数组长度依题意而定)。这个数组记录了每个人的上级是谁。

在这里插入图片描述

1、用集合中的某个元素来代表这个集合,则该元素称为此集合的代表元;

2、一个集合内的所有元素组织成以代表元为根的树形结构;

3、对于每一个元素 x,fa[x] 存放 x 在树形结构中的父亲节点(如果 x 是根节点,则令fa[x] = x);

4、对于查找操作,假设需要确定 x 所在的的集合,也就是确定集合的代表元。可以沿着fa[x]不断 在树形结构中向上移动,直到到达根节点。

因此,基于这样的特性,并查集的主要用途有以下两点:

1、维护无向图的连通性(判断两个点是否在同一连通块内,或增加一条边后是否会产生环);

2、用在求解最小生成树的Kruskal算法里。将图中的每个edge按照权重大小进行排序,每次从边 集中取出权重最小且两个顶点都不在同一个集合的边加入生成树。如果这两个顶点都在同一集合内, 说明已经通过其他边相连,因此如果将这个边添加到生成树中,那么就会形成环。

散列表

1、散列表定义

  • 基本思想

查找元素记录的存储位置与关键字之间存在对应关系;

以数据对象的关键字key为自变量,通过一个确定的函数关系h,计算出对应的函数值h(key),把这 个值解释为数据对象的存储地址,并按此存放,即“存储位置 = h(key)”。 优点:查找速度极快O(1),查找效率与元素个数n无关。

在这里插入图片描述

根据哈希函数H(k)=k%17;

查找key=42,则访问H(42)=42%17=8号地址,若内容为42则成功;

若查不到,则返回一个特殊值,如空指针或空记录。

可能将不同的关键字映射到同一个散列地址上,即h(keyi) = h(keyj),但是 keyi≠keyj,这 种现象称为“冲突(Collision)”,keyi和keyj称为“同义词(synonym)” 。 有6个元素的关键码分别为:(14,23,39,9,25,11)。

哈希函数:H(k)=k mod 7;

地址编码从0-6;

在这里插入图片描述

2、散列表的构造

  • 在构造前考虑两个方面:

​ 1、构造好的散列函数,避免浪费空间;

​ 2、制定一个好的解决冲突的方案。

  • 构造方法:

​ 根据元素集合的特性构造:

1、地址空间尽量小;

2、均匀。

在这里插入图片描述

  • 直接定址法

Hash(key) = a·key + b (或Hash(key)=key)(a、b为常数))

优点:以关键码key的某个线性函数值为哈希地址,不会产生冲突;

缺点:要占用连续地址空间,空间效率低。

在这里插入图片描述

  • 除留余数法

在这里插入图片描述

3、散列表冲突的处理

在这里插入图片描述

  • 开放定址法

基本思想:有冲突时就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总能找 到,并将数据元素存入。

在这里插入图片描述

在这里插入图片描述

优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素。

缺点:可能使第i个哈希地址的同义词存入第i+1个地址,这样本应存入第i+1个哈希地址 的元素变成了第i+2个哈希地址的同义词,……,产生“聚集”现象,降低查找效率。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、查找效率的分析

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值