#pragma once #include #include "Node.h" #include template class BTree { private: Node* root; int t; //*B-树的阶数(节点最大元素数的一半) //这里的t最后体现在每个节点上都是t - 1 到 2t - 1 void splitChild(Node* _node, int _n); void insertNonFull(Node* _node, const T& _key); void inorder(Node* _n) { if (!_n) return; int i = 0; //关注中序的时候:inorder(children[0]) -> inorder(key[0]) -> inorder(children[1])... 这样保证升序 for (i = 0; i < _n->keys.size(); i++) { if (i < _n->children.size()) inorder(_n->children[i]); std::cout << _n->keys[i] << " "; } //已经i++ if (i < _n->children.size()) inorder(_n->children[i]); std::cout << std::endl; } public: BTree() = delete; BTree(int _t) : t(_t), root(nullptr) {} void display() { inorder(root); } void insert(const T& _key); bool search(Node* _node, const T& _key); void erase(const T& _key); }; template inline void BTree::splitChild(Node* _pt, int _i) { //_pt-父节点//_i-第几个子节点//t-中间元素 Node* p = _pt->children[_i]; Node* tmp = new Node(p->isLeaf); int mid = t - 1; //复制mid右侧 for (int i = 0; i < mid; i++) { tmp->keys.push_back(p->keys[t + i]); } //不是叶子节点-复制孩子 if (!p->isLeaf) { for (int i = 0; i < t; i++) { tmp->children.push_back(p->children[i + t]); } } T middlekey = p->keys[mid]; //保留左侧 p->keys.resize(mid); if (!p->isLeaf) p->children.resize(t);//t = mid + 1 //增加孩子 _pt->children.insert(_pt->children.begin() + _i + 1, tmp); //提取中间元素插入上面 _pt->keys.insert(_pt->keys.begin() + _i, middlekey); } template inline void BTree::insertNonFull(Node* _node, const T& _key) { int i = _node->keys.size() - 1; //是叶子节点-先插入后排序O(n) if (_node->isLeaf) { _node->keys.push_back(_key); //向后移位 while (i >= 0 && _node->keys[i] > _key) { _node->keys[i + 1] = _node->keys[i]; i--; } _node->keys[i + 1] = _key; } //不是叶子节点,递归向下寻找叶子节点 else { while (i >= 0 && _node->keys[i] > _key) { i--; } i++;//找到children位置 //节点满了先分裂 if (_node->children[i]->keys.size() == 2 * t - 1) { splitChild(_node, i); //分裂提升后可能改变关键字位置 if (_key > _node->keys[i]) i++; } insertNonFull(_node->children[i], _key); } } template inline void BTree::insert(const T& _key) { //1-树空无root if (!root) { root = new Node(true); root->keys.push_back(_key); } //2-有root正常插入 else { //root满,分裂根节点 //重点关注:插入的时候,不管关键字是否上升到根节点,如果根节点满了,都要分裂以防万一 if (root->keys.size() == 2*t - 1) { Node* _root = new Node(false); _root->children.push_back(root); splitChild(_root, 0); root = _root; } //继续执行 insertNonFull(root, _key); } //当 t = 2,root 目前有 2 个元素,插入一个新元素后,root 会变成 3 个元素(满节点)。此时还不会分裂,分裂逻辑只在下一次插入超过 3 个元素时触发。 } template inline bool BTree::search(Node* _node, const T& _key) { //可以递归做 Node* tmp = _node; int i = 0; while (tmp->keys[i] < _key && i < tmp->keys.size()) i++; if (tmp->keys[i] == _key) return true; if(tmp->isLeaf) return false; return search(_node->children[i], _key); } template inline void BTree::erase(const T& _key) { //1-删除叶子 }