真c++创建B树(非c with class)

  首先要感谢清华大学邓公的教材(数据结构c++语言版第三版)和视频
  邓公的视频网址如下:https://next.xuetangx.com/course/THU08091002048/1515966

  由于邓公实现b树是用自定义的vector实现,网上大部分也都是用数组实现。我尝试了一下用stl的vector实现。也能实现b树的功能。
  在此,为了方便,用了一些教材中的插图(侵删)

如果要看懂此代码,你需要拥有的基础为:

  • 对c++模板有基本了解
  • 对c++stl中的vector有一定了解
  • 熟悉stl迭代器,逆向迭代器的用法,在本代码的查找,插入和删除操作中,用了大量的迭代器操作,如果你不熟悉,可能会有点绕。
  • 对c++11的新特性,如auto ,lambdas,基于范围的for循环等有所了解

  本代码在vs2019版能运行,其他平台未测试,但应该能支持c++11的编译器都能运行。如果你没接触过b树,要理解本代码,你至少需要一个小时甚至以上,b树真的十分复杂。

此B树只适合存放不相同元素,如果想放相同的元素,请自行改进。


一.B树的定义~

1.多路搜索树~

比如以二叉搜索树(BST)的两层为间隔,将各节点与其左右孩子合并成一个大节点,就能得到一个四路搜索树
在这里插入图片描述
当以三层为间隔时,可以得到八路搜索树。因此可以推广到2^k路搜索树

接下来的代码,能创建任意路搜索树,如果创建的为4路搜索树,我们不妨称之为(2,4)树

2.多路平衡搜索树~

若树中所有叶节点的深度均相等,就可以称之为多路平衡搜索树
深度即从根节点到这个节点的长度。
如下图所示
在这里插入图片描述

3.B树的性质~

  1. 所有叶节点的深度均相等。
  2. B树的阶次:比如(2,4)树,其阶次为4。以及(2,3)树,其阶次为3。
  3. 关键码:B树中一个节点所存的数值即为关键码。
  4. 孩子个数:B树的一个节点可拥有的孩子个数。(如一个节点至少拥有的孩子个数为2,最多拥有的孩子个数为3,则为(2,3)树)。
  5. 阶次和孩子个数的关系:如果B树的阶次为m,那么其孩子的个数范围为⌈m/2⌉(取上界)到m之间。 此点对于B树而言至关重要
  6. 孩子个数和关键码的关系:简单观察不难发现,B树的关键码数等于并且必然等于孩子个数减一
  7. B树的根节点,不受此限制,在非空的B树中,根节点关键码数至少为1,孩子个数至少为2。
  8. 若B树为空,其根节点的关键码数为0,孩子个数为1。

举例说明:
即在一颗4阶的B树中,其孩子个数至少为2,最多为4.关键码个数至少为1,最多为3.
即在一颗3阶的B树中,其孩子个数至少为2,最多为3.关键码个数至少为1,最多为2.

二.B树节点类~

  1. 从B树的结构和性质来看,在B树节点中,至少需要一个存放关键码的容器和一个存放孩子节点的容器。

  2. 所以我们把同一节点的所有孩子组织为一个vector,各相邻孩子之间的关键码也组织为一个vector。当然,按照B-树的定义,孩子vector的实际长度总是比关键码vector多一

  3. 为了方便插入和删除,同样也需要一个parent指针,来指向父节点。

  4. 同样,为了规范,将节点定义包含在一个命名空间my_btree里面。

  5. 由于没有在堆区构造,所以不需要写析构函数来delete

BTNode.h~

#pragma once
#include <vector>
using std::vector;

namespace my_btree {
   

	/*B-树节点模板类*/
	template<typename T = int>
	class BTNode {
   
	public:
		using BTNodePtr = BTNode<T>*;

	public:
		BTNodePtr _parent;//父节点
		vector<T> _key;//关键码vector
		vector<BTNodePtr> _child;//孩子vector,其长度总比key多一

	private:
		int _order;//B树的order,方便扩容//可不要这个,让vector自动扩容

	public:
		//用于创建根节点,初始时有0个关键码和一个空孩子指针
		BTNode(int order=3) :_order(order),_parent(nullptr), _key(0){
   
			_key.reserve(order);//并且给key和child的vector预留容量//用空间换时间。
			_child.reserve(order + 1);
			_child.push_back(nullptr);
		}
	};//class BTNode

}//namespace my_btree

三.B树类~

(一)定义变量和接口~

1.需要的变量

	int _size;//存放的关键码总数
	int _order;//B-树的阶次,比如3阶b树,可以在构造的时候进行修改。
	BTNodePtr _root;//根节点
	BTNodePtr _hot;//BTree::search()最后访问的非空(除非树空)的节点位置

如果看过邓老师的课的同学,应该能明白_hot节点的作用。在这里我简单解释一下_hot的作用。即其对应查找之后,访问的最后一个非空节点位置。有了_hot,节点的插入和删除操作就能变得更加简单。

2.需要的接口

构造函数
析构函数
查找
插入
删除
遍历(前序遍历,方便看结果)
其他接口如 获取阶次,返回规模,判空,返回根节点等。

3.必备的辅助函数

因插入而造成节点上溢所需的解决上溢函数
因删除而造成节点下溢所需的解决下溢函数

4.BTree.h~

为了方便起见,以下均以3阶b树为基准
#pragma once
#include "BTNode.h"
#include <algorithm>
using std::cout;
using std::endl;

namespace my_btree{
   
	template<typename T=int>
	class BTree {
   
	public:
		using BTNodePtr = BTNode<T>*;

	protected:
		int _size;//存放的关键码总数
		int _order;//B-树的阶次,比如3阶b树,可以在构造的时候进行修改。
		BTNodePtr _root;//根节点

		BTNodePtr _hot;//BTree::search()最后访问的非空(除非树空)的节点位置

	protected:
		void solveOverFlow(BTNode<T>*);//处理因插入而上溢之后的分裂处理
		void solveUnderFlow(BTNode<T>*);//处理因删除而下溢之后的合并处理

	public:
		BTree(int order=3):_order(order),_size(0),_root(new BTNode<T>(_order)),_hot(nullptr){
   }

		~BTree() {
   
			if (_root)
			{
   
				delete _root;
				_root = nullptr;
			}
		}

	public:
		constexpr int order()const {
   //获取阶次
			return _order;
		}

		constexpr int size()const {
   
			return _size;
		}

		inline BTNodePtr root()const{
   //返回树根
			return _root;
		} 

		constexpr bool empty()const {
   
			return !_root;
		}

	public:
		BTNode<T>* search(const T& data);//查找

		bool insert(const T& data);//插入

		bool remove(const T& data);//删除

	public:
		void show_BTree(BTNode<T>* BT)const;

	};//class BTree
}//namespace my_btree

(二)B树查找~

1.代码~

  从根节点开始,通过关键码的比较不断深入至下一层,直到某一关键码命中(查找成功),或者到达某一外部节点(查找失败)。
在这里插入图片描述
  此时各节点内通常都包含多个关键码,故有可能需要经过多次比较,才能确定应该转向下一层的哪个节点并继续查找。
  如果查找失败,返回不大于data(图中的key)的最大节点(由于节点数最多也不过几百个,故用顺序查找还是二分查找,都可以,这里用的是顺序查找)。从而转至下一层,直到找到或者到达叶子节点

  由于c++标准库并没有提供find_last的算法给vector使用。因此返回不大于data的最大节点,我用的是逆向迭代器结合find_if算法,并结合lambdas表达式作为仿函数来实现。

  并且由于标准库中的算法,需要传的是迭代器,返回的也是迭代器,因此,如果你对迭代器不是很懂,那么就建议你看看邓公原版的代码,那个稍微容量理解点。

	template<typename T>
	BTNode<T>* BTree<T>::search(const T& data)
	{
   
		BTNode<T>* v = _root;//从根节点出发
		_hot 
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值