【数据结构】动态查找表— B-树和B+树

简介: 【数据结构】动态查找表— B-树和B+树

一、什么是 B-树和B+树?


B树即B-树


一个m阶(它的每个节点最多包含m个孩子,m就是B树的阶)的B树具有以下特征:


1.  根节点至少含有两个子女。


2.  每个中间节点都包含k-1个元素和k个孩子,其中m/2 <= k <=m。


3.  每个叶子节点都包含k-1个元素,其中m/2 <= k <= m。


4.  所有的叶子节点都位于同一层,叶子节点不包含任何关键信息。


5.  每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划分。


B+树


一个m阶的B+树具有以下特征:


1. 有k个子树的中间节点包含有k个元素(B树是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点中。


2. 所有的叶子节点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子节点本身依关键字的大小自小而大顺序链接。(链表)


3. 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。


4. B+树查找时是自上向下查找,B-树是从下向上查找(中序遍历)。


需要注意的是:根节点的最大元素就是整个B+树的最大元素,以后无论插入删除多少元素,始终要保持最大元素在根节点中。每个叶子节点都带有指向下一个节点的指针,形成了一个有序链表。


二、B-树


1)B-树概述


B- 树是一种能够高效解决较大的、存放在外存储器上的文件的一种数据结构。


B-树是多路平衡查找树,它是一种特殊的多叉树,适合在磁盘等直接存取设备上组织动态的查找表。


在文件系统中,B-树已经成为索引文件的一种有效结构。


2)B-树定义


一颗m阶(m≥3)B-树,或为空树,或为满足下列特征的m叉树。


树中每个结点至多有m棵子树(分支)


若根节点不是叶子结点,则至少有2棵子树(分支)


所有的非终端结点中包含下列信息:(n,P0,K1,P1,K2,P2,...,Kn,Pn)


Ki  ( 1 ≤ i ≤ n ) 为关键字,且Ki < Ki+1  (每个结点关键字有序,从小大大)


Pj ( 1 ≤ j ≤ n ) 为指向子树根节点的指针,且Pj所指子树中所有结点的关键字值均小于Kj+1,Pn所指子树中所有结点的关键字值均大于Kn (例如:P0的子树的所有关键,都比K1小)


n ( ⌈m/2⌉-1 ≤ n ≤ m-1) 为关键字个数 , 3阶关键字个数 1≤n≤2 , 5阶关键字个数 2≤n≤4 (每一个子树都是通过分裂获得的,分裂出来子树结点个数,必然是一半减一 ⌈m/2⌉-1 )


每一个结点有n个关键字,必然包含 n + 1 为子树。


2b33a759a45e4b4cb3d70ceb472ee7d1.png


除根节点之外所有的非终端结点至少有 ⌈ m/2 ⌉ 棵子树(分支),即每个非根节点至少应有 ⌈ m/2 ⌉ -1个关键字


所有的叶子结点都出现在同一层次上,并且不带信息。


3阶B-树示意图如下:


84034f4702a241628d3947265a774b20.png


4阶B-树示意图如下:


38aed312a313495da333647047e5fb5a.png


3)相关类


B-树中的结点类:

class Node<T>  {            //B-树结点
     public int keyNum;         //关键字个数域
     public boolean isLeaf;     //是否为树叶
     public T[] key;            //关键字数组
     public Node[] child;       //子树指针数组
     public Node parent;        //双亲结点地址
     Node(int m) {          //构造方法
         keyNum = 0;
         isLeaf = true;
         key = (T[]) (new Object[ 2*m - 1]);
         child = new Node[ 2*m];
         parent = null;
     }
}

查找关键码时,返回的查找结果类

class Result {          //B-树查找结果类型     
     public Node resultNode;   //指向找到的结点
     public int i;             //在结点中的关键码序号
     public boolean found;     //true:找到  false:未找到
}

B树类:

public class BTree<T>{
    private Node<T> root = null;   //根结点
    private int degree;
    public BTree(int t)
    {
        degree = t;
    }
 }

4) 基于B-树的查找:分析


从根节点出发,沿指针搜索结点和在结点内进行顺序(或折半)查找两个过程交叉进行。


若查找成功,则返回指向被查关键字所在结点的地址和关键字在结点中的位置


若查找不成功,则返回null


假设指向B-树根节点的指针用root表示,待查找的关键字用于key表示,返回结果为Result(resultNode, i , found)


若找到,则fount=true,resultNode 结点汇总第i个关键字等于key


若未找到,则found=false,等于key的关键字应插入在resultNode所指向结点中第i和第i+1个关键字之间。


5)基于B-树的查找:算法


代码

 /**
 * 在B-树t上搜索指定的关键码key
 * @param key 要搜索的关键码键值
 * @param root 要搜索的B-树根结点
 * @return 返回结果(resultNode,i,found)
 * @return 若找到,则found=true,resultNode结点中第i个关键码等于Key
 * @return 若未找到,则found=false,等于key的关键码应插入在resultNode所指结点中第i和第i+1个关键码之间
 */
public Result searchBTree(Node<T> root, T key) {
    int i=0;
    Node<T> p=root,q=null;           //p指向待查结点,q指向p的双亲结点
    boolean found=false;
    Result rs = new Result();      //存放查找结果
    Comparable<T> k = (Comparable<T>) key;
    while (p!= null && !found) {
        i=0;
        // 将i移动到关键字所在的分支
        while(i < p.keyNum && k.compareTo((p.key)[i])>0)
            i++;
        if (i < p.keyNum  && k.compareTo((p.key)[i])==0)
            found=true;        //找到
        else
        {
            q=p;             //保存双亲结点
            p=p.child[i];    //在子树中查找
        }
     }
   if(found==false)                   
        p=q;
    rs.resultNode=p;
    rs.i=i;
    rs.found=found;
    return rs;
}

6)基于B-树的插入运算


在查找不成功之后,需进行插入。显然,关键字插入的位置必定在最下层的非叶结点,有下列几种情况:


插入后,该结点的关键字个数 n < m,不修改指针


==插入后==,该结点的关键字个数 n = m,则需进行“结点分裂”,令 ==s= ⌈ m/2 ⌉==,


在原结点中保留 (P0,K1,P1,...,Ks-1,Ps-1),构建左子树 ,


在建新结点 (Ps,Ks+1,...,Kn,Pn) ,构建右子树,


最后将(Ks,p)插入双亲结点。


若双亲结点 n=m,继续进行第2步


若双亲为空,则建新的根结点。


构建:3阶B-树


73126f9435b942d59fe169d5e7bc91e7.png


构建:4阶B-树


53c639e22dc647fdacee36f2fac8222c.png


构建:5阶B-树


bd1647f7248a475c84f52dcb8b5f73ca.png


7)基于B-树的删除运算


在B-树上删除一个关键字,首先找到该关键字所在结点的位置,具体可分下面两种情况:


被删除结点Ki是最下层的非终端结点(即叶子结点的上一层),则应删除Ki及它的右边的指针;删除后若结点中关键字个数不少于⌈ m/2 ⌉-1,则删除成功;否则要进行合并结点操作。


待删除结点是最下层的非终端结点以上某个层次的结点,根据B-树的特性,可以用Ki右边指针Pi所指子树中最小关键字Y代替K,然后在相应的结点中删除Y。


删除B-树中最下层的非终端结点的关键字,分为以下3种情况:


被删除关键字所在结点的关键字个数不小于⌈ m/2 ⌉,则只需从该结点中删除关键字Ki相应的指针Pi,树的其他部分保持不变。


被删除关键字所在结点的关键字个数等于⌈ m/2 ⌉-1,而与该结点相邻的右兄弟(或左兄弟)结点中的关键字个数大于⌈ m/2 ⌉-1,则需将其右兄弟的最小关键字(或其左兄弟的最大关键字)上移到双亲结点中,而将双亲结点中小于(或大于)该上移关键字的关键字下移到被删关键字所在的结点中。


被删除关键字所在结点的关键字个数和其相邻的兄弟结点中的关键字个数均等于⌈ m/2 ⌉-1,此时需将被删关键字的所在结点与其左或右兄弟合并。


3阶删除:


最下层非终端结点


b0d8709124234056866bc60c74cc9f3a.png


最下层非终端结点以上:删除85

f0ecd08bd8d547f1b1ab260d3b349db3.png

综合:删除70


bbc17b8fdebc4a38952403b28f2fe4e4.png


4阶删除


最下层非终端结点


f03953e543554c95b91fd1104463ce3d.png


最下层非终端结点以上:删除9和85


b80cc19fa40345a0881ab447c9222652.png


综合:删除 70


d3b654dcdbe54c68b48a50a16b8c85eb.png


5阶删除


最下层非终端结点


b6dd8832ebf643b48b120571f0c4b59b.png


最下层非终端结点以上:删除 84


e838e46d53ff43788b0c9d8524438201.png


综合:删除 70


21c4812f2f0f4eb5b318d88ba8c6609a.png


综合2:删除70


bb3f1aa66b1a49ab94c0c70358f2e77e.png


8)性能分析


在B-树中进行查找时,其查找时间主要花费在搜索结点(访问外存)上,即主要取决于B-树的深度。


由于除根节点外的每个非终端结点至少有⌈ m/2 ⌉棵子树 ,... ,第h+1层至少2×⌈ m/2 ⌉h-1个结点。


在含n个关键字的m阶B-树上最大深度不超过 log⌈ m/2 ⌉((n+1)/2) + 1


三、B+树


B+树是B-树的一种变型


每个叶子结点中含有n个关键字和n个指向记录的指针;并且,所有叶子结点彼此相链接构成一个有序链表,其头指针向含最小关键字的结点;


每个非叶结点中的关键字Ki即为其相应指针Pi所指子树中关键字的最大值


所有叶子节点都处在同一层次上,每个叶子结点中关键字的个数均介于⌈ m/2 ⌉和m之间


在B+树上,既可以进行缩小范围的查找,也可以进行顺序查找


1. 在进行缩小范围的查找时,不管成功与否,都必须查到叶子结点才能结束


2. 若在结点内查找时,给定值 ≤ Ki,则应该继续在Pi所指子树中进行查找


类似于B-树进行,即必要时,也需要进行结点的“分裂”或“归并”


相关文章
|
1月前
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
53 0
|
27天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
53 5
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
89 16
|
1月前
|
算法
数据结构之文件系统模拟(树数据结构)
本文介绍了文件系统模拟及其核心概念,包括树状数据结构、节点结构、文件系统类和相关操作。通过构建虚拟环境,模拟文件的创建、删除、移动、搜索等操作,展示了文件系统的基本功能和性能。代码示例演示了这些操作的具体实现,包括文件和目录的创建、移动和删除。文章还讨论了该算法的优势和局限性,如灵活性高但节点移除效率低等问题。
54 0
|
2月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
32 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
2月前
|
Java C++
【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
42 0
|
2月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
34 0
|
2月前
05(数据结构考研)树相关操作代码
05(数据结构考研)树相关操作代码
31 0
|
2月前
|
存储 算法 Java
数据结构和算法--分段树
数据结构和算法--分段树
25 0

热门文章

最新文章