注意:以下均用2-3树指代2-3查找树

2-3树的定义:

  • 2-3树首先是一颗二叉查找树(BST树),也是一颗平衡二叉树(AVL树),所以同时包含两者的性质,
  • 2-3树是一颗完美平衡的二叉树,也就是说所有叶子结点到根结点的路径都相同
  • 2-3树中包含两种结点:2结点与3结点;如果是2结点,那么一定有一个值和两个孩子,如果是3结点,一定有两个值和3个孩子
  • 它是一颗最简单的B树

2-3树结点定义:

template<class T>
class tree_23_node                    //2-3树的结点
{public:tree_23_node();public:int m_type;                       //用于记录结点的类型,如果是2结点,那么m_type=2,如果是3结点,m_type=3,否则m_type=0;T* m_small_data;T* m_large_data;class tree_23_node<T>*m_parent;             //父结点class tree_23_node<T>*m_l_child;            //左孩子class tree_23_node<T>*m_m_child;           //中孩子class tree_23_node<T>*m_r_child;            //右孩子
}template<class T>
class tree_23                       //2-3树
{public:tree_23();public:class tree_23_node<T>*m_root;
}

上图是一颗简单的2-3树,2-3树中序遍历的顺序为:左孩子->当前结点小值->(中结点->当前结点大值)->右孩子,

其中序遍历结果是:8  10  12  14  16  20  24  26  28  32  34  38

查找:

  2-3树的查找操作和二叉树的查找操作是一样的,

  • 检查当前结点的值,如果当前结点命中,返回true,退出递归;否则向左子树递归查找
  • 如果左子树命中,返回true,退出递归;(如果中子树存在)否则向中子树递归查找
  • 如果中子树命中,返回true,退出递归;否则向右子树递归查找
  • 如果右子树命中,返回true,退出递归;否则当前结点、左子树、(如果存在)中子树、右子树都没有命中,返回false

插入:

  注意:2-3树的长高发生在根结点,而不是叶子结点

  普通二叉树的插入操作:假设插入的值为data,

  • 先找到要插入的叶子结点位置,此叶子结点设为leaf,值为leaf-value
  • 新建结点son ,son-value=data,son-l-child=son-r-child=NULL(son的左右孩子都是NULL)
  • 再判断leaf-value和data的大小,如果data>leaf-value,则son到leaf的右子树中,否则son到leaf的左子树中
  • 注意在上一步时树的高度变化了(树高+1),也就是说树的高度变化发生在叶子结点leaf

2-3树插入分析:假设插入的值为data,

  • 先找到要插入的叶子结点位置,此叶子结点设置为leaf,
  • 如果此时新建结点son,son-value=data,插入到leaf的一颗子树中,2-3树的性质(所有叶子结点到根结点的路径都相同)不会满足
  • 所以不能新建结点,而是要把data插入到叶子结点leaf中,这样(所有叶子结点到根结点的路径都相同)这条性质可能不会满足
  • 如果leaf是2结点,新值data直接插入到leaf,如果leaf是3结点,不能插入新值data,那么将leaf分裂向上(leaf的父结点)递归处理
  • 如果递归到根结点,而根结点也是3结点,那么分裂根结点后,树的高度+1,也就是说2-3树的长高发生在根结点,而不是叶子结点

2-3树插入操作:假设插入的值为data,

  1. 如果根结点是NULL,直接将data插入根结点
  2. 否则先找到data需要插入的叶子结点leaf
  3. 如果如果插入结点leaf是2结点,直接插入data,leaf变为3结点
  4. 如果插入结点leaf是3结点,向上(parent)递归寻求解(假设leaf的父结点为parent)
    1. 如果parent是2结点,这是情况2,直接插入parent并return
    2. 如果parent是3结点,这是情况3,继续向向上(parent->parnet)递归求解
    3. 如果parent是结点,单独处理
  • 插入操作----情况1:根结点root==NULL,直接将data插入到根结点,根结点变为2结点
  • 插入操作----情况2:根结点root!=NULL,首先找到插入的叶子结点leaf,  

情况2.1:leaf是2结点,直接向leaf插入data   

情况2.2:leaf是3结点,但是leaf的parent是2结点,(注意这里的leaf的孩子是NULL空指针,没有画出来)

情况2.2分析:

由于leaf是3结点,如果直接将9插入到leaf中,那么leaf会变成4结点(leaf会有3个值,4个孩子),不符合2-3树的性质;

解决办法:

  • 将leaf中的两个值(small和large两个值)和data比较大小
  • 最小的值作为leaf->m_small_data,并且leaf变为2结点,leaf->m_large_data=NULL
  • 中间值作为新的data,最大值新建一个结点new_node
  • 将data和new_node作为形参往parent递归下去(对parent递归)
  • 如果parent是2结点(包含一个键值和两个孩子),将data(键值)和new_node(孩子)与parent的一个键值和两个孩子组合为一个3结点(2个键值和3个孩子)
  • 如果parent是3结点,就是下面的情况2.3    

如下面的3张图,在创建  新的键值data和新的孩子new_node   时,要考虑数值之间的大小关系,详情见下面的图,并且data和new_node在和parent组成3结点时也要考虑清楚各种情况,总之很繁琐

情况2.3:leaf是3结点,但是leaf的parent也是3结点,(注意这里的leaf的孩子是NULL空指针,没有画出来)

情况2.4:leaf是3结点,但是leaf的parent也是3结点,并且parent是根结点

2-3树中插入的注意事项

1、当前结点分裂形成新的当前结点、新建结点、新值时,一定不能丢失所有的孩子信息,其中当前结点有3个孩子,以及上传的一个孩子(是什么呢?它是前一个新建结点,可以是NULL),共4个孩子,可以形成两个2结点

2、如果是根结点的分裂,要将根结点的m_root的指向及时更新

3、2-3树的长高只能通过根结点的分裂

删除:

  注意:2-3树的逆生长(即高度降低)一定使发生在根结点,而不是叶子结点

  普通二叉树的删除操作假设删除的值为data

  • 首先是找到待删除结点的位置
  • 如果待删除结点是叶子结点,直接删除
  • 如果待删除结点是非叶子结点,分情况讨论:
    1. 待删除结点只有一个孩子,那么直接将父结点和孩子结点建立联系即可
    2. 待删除结点有两个孩子,找到当前结点的前驱(后继)结点,两结点替换,继续对前驱结点进行结点删除操作

  2-3树的删除操作:假设删除的值为data

  1. 首先找到待删除结点的位置
  2. 如果待删除结点不是叶子结点,将问题转化为删除叶子结点(通过与前驱或者后继结点替换来转换问题)
  3. 如果待删除结点是叶子结点,
    1. 如果删除结点是3结点,直接删除data,删除结点变为2结点,然后return
    2. 如果删除结点是2结点,首先删除data,删除结点变为0结点
      1. 如果父兄都是2结点,递归处理
      2. 如果父兄至少有一个是3结点,从父结点或者兄弟结点借值后组建新的删除结点(变为2结点),然后return

  下面我将通过图示来说明:待删除2-3树如下

删除操作----情况1如果待删除结点不是叶子结点,将问题转化为删除叶子结点

删除操作----情况2:如果待删除结点是叶子结点

情况2.1:删除结点是3结点,直接删除data,删除结点变为2结点,然后return

情况2.2:删除结点是2结点,直接删除data,删除结点变为0结点

情况2.2.1:如果父兄至少有一个3结点,从父结点或者兄弟结点借值后组建新的删除结点(变为2结点),然后return

这种情况是最繁琐的,要分父兄都是2结点、父是2结点兄是3结点、父是3结点兄是2结点这3种情况考虑,还要考虑delete是在父结点的左结点、结点还是右结点,但是具体的操作是一样的,太繁琐了就不具体讨论了,本人共考虑了16小情况,还没有找到简单的解法

情况2.2.2:如果父兄都是2结点,此时待删除结点是0结点,需要递归处理

如果说情况2.2.1是繁琐,那么情况2.2.2就很简洁了,这里我们定义以下0结点,0结点代表结点没有键值,但是不代表没有孩子(注意NULL也视为有一个小孩),什么意思呢?看下面的图示

2-3树中删除的注意事项

1、通过将delete结点从叶子结点向根结点移动,不断地判断delete结点的父兄结点符合哪种状况,如此递归下去,直到找到问题的出口并return,

2、注意当delete的父结点是NULL,那么树逆生长(树的高度-1),这就是2-3树的逆生长(即高度降低)一定使发生在根结点,而不是叶子结点

3、在结点的融合过程中,时刻注意更新每个结点的信息,包括结点类型,结点值,结点的父结点以及子结点

结尾:

作为最简单的B树,2-3树的实现仍然很繁琐,2-3-4树就更加麻烦了,且创建一颗2-3(-4)树的效率可能不尽如人意,而且红黑树作为2-3(-4)树的变种,红黑树的插入和删除更高效快捷,那么理解并且用代码实现2-3树似乎不重要了,但是理解2-3树对理解红黑树是有很大的帮助的,红黑树中的插入情况可以和2-3树中的插入、删除情况有所区别,但区别不大。

本人的2-3树代码太冗长了,就不发出来了。

2-3树的插入和删除操作相关推荐

  1. 快速了解B+树的插入、删除操作

    B+树非常的复杂,这里不进行详细的讲解,只对基本的插入删除操作进行说明. 在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶节点用指针连接.因此在进行插入删除操作时,要进行调整, ...

  2. AVL树的插入_删除操作实现~

    AVL的插入操作:找到所插位置之后,往上寻找可能发生不平衡之处x,若找到x则调整平衡.顶多调整平衡1次. AVL的删除操作:找到删除结点x,类似于二叉查找树一样找到其后继或前驱y,若为x->ri ...

  3. B树的插入、删除操作

    一.简介 B树是什么? 1970年,R.Bayer和E.mccreight提出了一种适用于外查找的树,它是一种平衡的多叉树,称为B树(或B-树.B_树). 一棵m阶B树(balanced tree o ...

  4. 目录树 删除 数据结构_数据结构:B树和B+树的插入、删除图文详解

    B树 1.1B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数.当m取2时,就是我们常见的二叉搜索树. ...

  5. 数据结构:B树和B+树的插入、删除图文详解

    目录 B树 1.1B树的定义 1.2B树的插入操作 1.3B树的删除操作 B+树 2.1 B+树的定义 2.2 B+树的插入操作 2.3 B+树的删除操作 B树 1.1B树的定义 B树也称B-树,它是 ...

  6. 彻底理解面试难点之rb-tree(红黑树)续--对红黑树的插入和删除操作的一些理解!!!

    这里主要讲一下对红黑树的插入和删除操作的一些理解 对于红黑树的一些相关性质的介绍,上篇已经讲了,这里不再介绍,有需要了解的,可以翻前面的博客看看. 1.红黑树的插入操作 对于红黑树的元素插入,我们首先 ...

  7. 红黑树及其插入、删除操作

    在二叉搜索树中,基本操作如结点的插入.删除.查找的性能上界都得不到保证,原因在于二叉搜索树的构造依赖于其结点值的插入顺序,最坏情况下二叉搜索树会退化为单链表(如下图所示).因此我们需要对二叉搜索树做出 ...

  8. 二叉平衡树的插入和删除操作

    [转载]二叉平衡树的插入和删除操作 1.      二叉平衡树 二叉排序树查找.插入和删除操作的时间复杂度和树的深度n有关.构建树时,当先后插入的结点按关键字有序时,二叉排序树退化为单枝树,平均查找长 ...

  9. c语言二叉排序树的创建与查找,C语言实现二叉查找树的插入和删除操作问题求教...

    使用C语言实现二叉查找树的插入和删除操作,但在 return searchBST( T->rchild, val, f, p);出错.这里应该使用了双指针,求教应该怎么改才正确. /* +--- ...

最新文章

  1. wukong引擎源码分析之索引——part 1 倒排列表本质是有序数组存储
  2. python写的游戏怎么给别人玩-一步步教你怎么用python写贪吃蛇游戏
  3. 使用Javaslang进行Java 8中的函数式编程
  4. 杜克大学计算机硕士要几年,2017杜克大学春季不招计算机专业的硕士?
  5. java想要生成 字符串,如何在Java中“优雅地”生成String?
  6. CentOS 6.4 命令行 安装 VMware Tools
  7. 优秀的电商平台Jshop栗子
  8. 【ACL2020-CMU-Google】MobileBERT:用于资源受限设备的任务无关“瘦版”BERT
  9. LEACH路由协议MATLAB仿真代码
  10. 临床大数据分析与挖掘
  11. 2021宇哥八套卷总结—第三套试卷分析
  12. Python办公自动化之文件读写操作与Excel,csv,PDF文件
  13. esxi 虚拟机的控制台上键盘无法输入
  14. u3d:200个插件免费分享
  15. java8:lambda级联表达式(Cascading)或柯里化(Currying)原理简化详解
  16. .net之实现文件上传与下载
  17. C# MVC 微信支付教程系列之公众号支付
  18. iOS关闭键盘的两种简单方法
  19. Android拉取微信公众号列表,Xposed实时获取微信公众号推送
  20. Android自定义的下拉列表框控件

热门文章

  1. 【长文慎入】百度阿里网易大疆等大小厂前端校招面筋
  2. 沪江论坛听力提高与交流路线图
  3. 计算机阵列除法器原理,计算机组成原理原码阵列除法器.doc
  4. 医学成像原理与图像处理一:概论
  5. C++学习日记12——设计模式
  6. SQL 如何获取时间最新的记录
  7. 三阶矩阵/行列式计算的新方法
  8. 从0开始写一个多线程爬虫(2)
  9. html 怎么让div卷角,css实现简约的纸张卷角效果
  10. Vim编辑器与shell脚本(.sh)