小工具知识网

当前位置: 首页 > 行业知识 > 408数据结构知识点——第七章 查找

行业知识

408数据结构知识点——第七章 查找

2026-11-09 19:40:52 来源:互联网转载

文章目录

    • 查找的基本概念
      • 基本概念
      • 对查找表的常见操作
      • 查找算法的评价指标
      • 顺序查找和折半查找
        • 顺序查找
          • 顺序查找的算法思想
          • 顺序查找的实现
          • 顺序查找的实现(哨兵)
          • 查找效率分析
          • 顺序查找的优化(对有序表)
          • 顺序查找的优化(被查概率不相等)
          • 折半查找
            • 折半查找的算法思想
            • 折半查找的实现
            • 查找效率分析
            • 分块查找
              • 分块查找的算法思想
              • 分块查找的实现
              • 查找效率分析
              • 树形查找
                • 二叉排序树
                  • 二叉排序树的定义
                  • 二叉排序树的查找
                  • 二叉排序树的插入
                  • 二叉排序树的构造
                  • 二叉排序树的删除
                  • 查找效率分析
                  • 平衡二叉树
                    • 平衡二叉树的定义
                    • 平衡二叉树的插入
                    • 调整最小不平衡子树
                    • 查找效率分析
                    • 平衡二叉树的删除
                    • 红黑树
                      • 为什么要发明红黑树
                      • 红黑树的定义
                      • 结点的“黑高”
                      • 红黑树的性质
                      • 红黑树的查找
                      • 红黑树的插入
                      • 红黑树的删除
                      • B树和B+树
                          • 5叉查找树
                          • 如何保证查找效率
                          • B树
                          • B树的高度
                          • B树的插入
                          • B树的删除
                          • B+树
                          • B树和B+树对比
                          • 散列表
                              • 散列表、散列函数
                              • 冲突、同义词
                              • 如何减少冲突
                              • 如何减少冲突
                              • 散列函数的构造
                                • 除留余数法
                                • 直接定址法
                                • 数字分析法
                                • 平方取中法
                                • 处理冲突的方法
                                  • 拉链法
                                  • 开���定址法

                                    注:内容参考王道2024考研复习指导以及《数据结构》

                                    查找的基本概念

                                    基本概念

                                    查找 —— 在数据集合中寻找满⾜某种条件的数据元素的过程称为查找。

                                    查找表(查找结构)—— ⽤于查找的数据集合称为查找表,它由同⼀类型的数据元素(或记录)组成。

                                    关键字 —— 数据元素中唯⼀标识该元素的某个数据项的值,使⽤基于关键字的查找,查找结果应该是唯⼀的。

                                    对查找表的常见操作

                                    1. 查找符合条件的数据元素
                                    2. 插入、删除某个数据元素

                                    只需进行操作1,为静态查找表,关注查找速度;

                                    操作1、2都需要进行,为动态查找表,除了查找速度,也要关注插/删操作是否方便实现。

                                    查找算法的评价指标

                                    查找长度——在查找运算中,需要对比关键字的次数为查找长度

                                    平均查找长度(ASL,Average Search Length)——所有查找过程中进行关键字的比较次数的平均值, A S L = ∑ i = 1 n P i C i ASL=\sum_{i=1}^{n}P_iC_i ASL=∑i=1n​Pi​Ci​(通常认为查找任何一个元素的概率都相同)

                                    顺序查找和折半查找

                                    顺序查找

                                    顺序查找的算法思想

                                    顺序查找,也叫“线性查找”,通常用于线性表。

                                    算法思想,从头到尾挨个查找。

                                    顺序查找的实现
                                    typedef struct{    ElemType *elem;    int TalbeLen;}SSTable;int Search_Seq(SSTable ST,ELemType key){    int i;    for(i=0;i    ElemType *elem;    int TalbeLen;}SSTable;int Search_Seq(SSTable ST,ELemType key){    ST.elem[0]=key;    int i;    for(i=ST.TableLen;ST.elem[i]!=key;i--);    return i;}    ElemType *elem;    int TableLen;}SSTable;int Binary_Search(SSTable L,ElemType key){    int low=0,high=L.TableLen-1,mid;    while(low        mid=(low+high)/2;        if(L.elem[mid]==key){            return mid;        }else if(L.elem[i]key){            high=mid-1;        }else {            low=mid-1;        }        return -1;    }}
                                    h5查找效率分析/h5 pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-250423013034555.png" //p p构造查找判定树/p p注:图中数字只是⼀个编号,并不是关键字的值/p pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-250423013034J3.png" //p ulli如果当前low和high之间有偶数个元素,则 mid 分隔后,左半部分⽐右半部分少⼀个元素。/lili如果当前low和high之间有奇数个元素,则 mid 分隔后,左右两部分元素个数相等p折半查找的判定树中,若 m i d = ⌊ ( l o w + h i g h ) / 2 ⌋ mid=\lfloor (low+high)/2 \rfloor mid=⌊(low+high)/2⌋,则对于任何⼀个结点,必有:右⼦树结点数-左⼦树结点数=0或1/p p折半查找的判定树一定是平衡二叉树。/p p折半查找的判定树中,只有最下面一层是不满的,因此,元素个数为n时树高 h = ⌈ log ⁡ 2 ( n + 1 ) ⌉ h=\lceil \log_2(n+1) \rceil h=⌈log2​(n+1)⌉/p pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-250423013035934.png" //p p A S L 成功 = ( 1 ∗ 1 + 2 ∗ 2 + 3 ∗ 4 + 4 ∗ 4 ) / 11 ASL_{成功}=(1*1+2*2+3*4+4*4)/11 ASL成功​=(1∗1+2∗2+3∗4+4∗4)/11=3/p p A S L 失败 = ( 3 ∗ 4 + 4 ∗ 8 ) 12 = 11 / 3 ASL_{失败}=(3*4+4*8)12=11/3 ASL失败​=(3∗4+4∗8)12=11/3/p h4分块查找/h4 h5分块查找的算法思想/h5 p分块查找,又称索引顺序查找,算法过程如下:/p olli在索引表中确定待查记录所属的分块(可顺序、可折半)/lili在块内顺序查找/li/ol p注:若索引表中不包含⽬标关键字,则折半查找索引表最终停在 low>high,要在low所指分块中查找。

                                    “索引表”中保存每个分块的最大关键字和分块存储区间。

                                    特点:块内无序,块间有序。

                                    分块查找的实现
                                    //索引表typedef struct{    ElemType maxValue;    int low,high;}Index;//顺序表存储实际元素ElemTyee list[100];
                                    查找效率分析

                                    假设,长度为n的查找表被均匀地分成b块,每块s个元素

                                    设索引查找和块内查找的平均查找长度分别为 L I 、 L S L_I、L_S LI​、LS​,则分块查找地平均查找长度为 A S L = L I + L S ASL=L_I+L_S ASL=LI​+LS​

                                    用顺序查找索引表,则 L I = 1 + 2 + . . . + b b = b + 1 2 , L S = 1 + 2 + . . . + s s = s + 1 2 L_I=\frac{1+2+...+b}{b}=\frac{b+1}{2},L_S=\frac{1+2+...+s}{s}=\frac{s+1}{2} LI​=b1+2+...+b​=2b+1​,LS​=s1+2+...+s​=2s+1​

                                    则 A S L = b + 1 2 + s + 1 2 = s 2 + 2 s + n 2 s ASL=\frac{b+1}{2}+\frac{s+1}{2}=\frac{s^2+2s+n}{2s} ASL=2b+1​+2s+1​=2ss2+2s+n​,当 s = n s=\sqrt{n} s=n ​时, A S L 最小 = n + 1 ASL_{最小}=\sqrt n+1 ASL最小​=n ​+1

                                    用折半查找查索引表,则 L I = ⌈ log ⁡ 2 ( b + 1 ) ⌉ , L S = 1 + 2 + . . . + s s = s + 1 2 L_I=\lceil \log_2(b+1) \rceil,L_S=\frac{1+2+...+s}{s}=\frac{s+1}{2} LI​=⌈log2​(b+1)⌉,LS​=s1+2+...+s​=2s+1​

                                    则 A S L = ⌈ log ⁡ 2 ( b + 1 ) ⌉ + s + 1 2 ASL=\lceil \log_2(b+1) \rceil +\frac{s+1}{2} ASL=⌈log2​(b+1)⌉+2s+1​

                                    树形查找

                                    二叉排序树

                                    二叉排序树的定义

                                    二叉排序树,又称二叉查找树(BST,Binary SearchTree)

                                    一棵二叉树或者是空二叉树,或者是具有如下性质的二叉树:

                                    • 左子树上所有结点的关键字均小于根结点的关键字
                                    • 右子树上所有结点的关键字均大于根结点的关键字
                                    • 左子树和右子树又各是一棵二叉排序树

                                      即,左子树结点值 int key; strcut BSTNode *lchild,rchild;}BSTNode,*BSTree;//非递归BSTNode *BST_Search(BStree T,int key){ while(T!=NULL && key!=T-key){ if(keylchild; else T=T-rchild; } return T;}//递归BSTNode *BSTSearch(BStree T,int key){ if(T==NULL){ return NULL; } if(key==T->key){ return T; }else if(keykey){ return BSTSearch(T->lchild,key); }else if(key>T->key){ return BSTSearch(T->rchild,key); }}

                                      二叉排序树的插入

                                      若原二叉排序树为空,则直接插入结点;否则,若关键字k小于根结点值,则插入到左子树,若关键字k大于根结点值,则插入到右子树

                                      int BST_Insert(BSTree &T,int k){    if(T==NULL){//原树为空,新插入的结点为根结点        T=(BSTree)malloc(sizeof(BSTNode));        T->key=k;        T->lchild=T->rchild=NULL;        return 1;//返回1,插入成功    }else if(k==T->key){//树中存在相同关键字的结点,插入失败       return 0;    }else if(kkey){//插入到T的左子树       return BST_Insert(T->lchild,k);    }else{//插入到T的右子树return BST_Insert(T->rchild,k);}}
                                      二叉排序树的构造

                                      不同的关键字序列可能得到相同的二叉排序树,也可能得到不同的二叉排序树。

                                      //按照str[]中的关键字序列建立二叉排序树void Creat_BST(BSTree &T,int str[],int n){    T=NULL;//初始时T为空树    int i=0;    while(i//依次将每个关键字插入到二叉排序树中        BST_Insert(T,str[i]);        i++;    }          }    int key;    int balance;    struct AVLNode *lchild,*rchild;}AVLNode,*AVLTree;
                                      h5平衡二叉树的插入/h5 p在二叉树排序树中插入新结点后,需要查找路径上所有结点,从插入点往回找到第一个不平衡的结点,调整以该结点为根的子树(最小不平衡树)。/p h5调整最小不平衡子树/h5 tabletheadtrth/thth调整最小不平衡子树A/th/tr/theadtbodytrtdLL/tdtd在A的左孩子的左子树中插入导致不平衡/td/trtrtdRR/tdtd在A的右孩子的右子树中插入导致不平衡/td/trtrtdLR/tdtd在A的左孩子的右子树中插入导致不平衡/td/trtrtdRL/tdtd在A的右孩子的左子树中插入导致不平衡/td/tr/tbody/table p调整最小不平衡子树(LL)/p pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-250423013035915.png" //p pLL平衡旋转(右单旋转)/p ulli由于在结点A的左孩子(L)的左子树(L)上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要一次向右的旋转操作。/lili将A的左孩子B向右上旋转代替A成为根结点,将A结点向右下旋转成为B的右子树的根结点,而B的原右子树则作为A结点的左子树。p调整最小不平衡子树(RR)/p pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-25042301303CL.png" //p pRR平衡旋转(左单旋转)/p ulli由于在结点A的右孩子(R)的右子树(R)上插入了新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。/lili将A的右孩子B向左上旋转代替A成为根结点,将A结点向左下旋转成为B的左子树的根结点,而B的原左子树则作为A结点的右子树。p代码思路/p pimg src="https://m.xiaogongju.com.cn/uploads/allimg/20250423/-25042301303C96.png" //p ulli p实现f向右下旋转,p向右上旋转:其中f是爹,p为左孩子,gf为f的爹(左旋、右旋操作后可以保持二叉排序树的特性)/p ullif-lchild=p-rchild;/lilip->rchild=f;
                                    • gf->lchild/rchild=p;
                                    • 实现 f 向左下旋转, p 向左上旋转:其中f是爹,p为右孩子,gf为f的爹

                                      • f->rchild = p->lchild;
                                      • p->lchild = f;
                                      • gf->lchild/rchild = p;

                                        调整最小不平衡子树(LR)

                                        LR平衡旋转(先左后右双旋转)

                                        • 由于在A的左孩子(L)的右子树(R)上插入新结点,A的平衡因

                                          子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转。

                                        • 先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后再把该C结点向右上旋转提升到A结点的位置。

                                          调整最小不平衡子树(RL)

                                          RL平衡旋转(先右后左双旋转)

                                          • 由于在A的右孩子(R)的左子树(L)上插入新结点,A的平衡

                                            因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转。

                                          • 先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置,然后再把该c结点向左上旋转提升到A结点的位置。
                                            查找效率分析

                                            若树高为h,则最坏情况下,查找一个关键字最多需要对比 h 次,即查找操作的时间复杂度不可能超过 O(h)

                                            平衡二叉树一一树上任一结点的左子树和右子树的高度之差不超过1。

                                            假设以 n h n_h nh​表示深度为h的平衡树中含有的最少结点数,则有 n 0 = 0 , n 1 = 1 , n 2 = 2 , 并且有 n h = n h − 1 , + n h − 2 + 1 n_0=0,n_1=1,n_2=2,并且有n_h=n_{h-1},+n_{h-2}+1 n0​=0,n1​=1,n2​=2,并且有nh​=nh−1​,+nh−2​+1

                                            可以证明含有n个结点的平衡二叉树的最大深度为 O ( log ⁡ 2 n ) O(\log_2n) O(log2​n),平衡二叉树的平均查找长度为 O ( log ⁡ 2 n ) O(\log_2n) O(log2​n)

                                            平衡二叉树的删除

                                            平衡二叉树的删除操作:

                                            • 删除结点后,要保持二叉排序树的特性不变(左 int key; RBnode* parent; RBnode* lchild; RBnode* rchild; int color;}; ElemType keys[4];//最多4个关键字 struct Node* child[5];//最多5个孩子 int num;//结点中有几个关键字};

上一篇:C++奇迹之旅:初始化列表与explicit

下一篇:最后不管怎么样英文怎么说?