#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) { if (!root) return; // 空树,直接返回 // 用一个递归 lambda 来实现删除逻辑 auto remove = [&](auto&& self, Node* node, const T& key) -> void { int idx = 0; // 找到第一个 >= key 的位置 while (idx < node->keys.size() && node->keys[idx] < key) idx++; // ============================================================== // 情况 1:key 存在于当前节点 node->keys[idx] // ============================================================== if (idx < node->keys.size() && node->keys[idx] == key) { // ---- 1.1 如果当前节点是叶子:直接删除即可 if (node->isLeaf) { node->keys.erase(node->keys.begin() + idx); } // ---- 1.2 如果是内部节点(非叶子) else { Node* leftChild = node->children[idx]; Node* rightChild = node->children[idx + 1]; // ① 如果左子树至少有 t 个关键字(够借用) if (leftChild->keys.size() >= t) { // 找到前驱(左子树最右边元素) Node* cur = leftChild; while (!cur->isLeaf) cur = cur->children.back(); T pred = cur->keys.back(); // 用前驱替换当前 key node->keys[idx] = pred; // 递归去左子树删掉前驱 self(self, leftChild, pred); } // ② 如果右子树至少有 t 个关键字(够借用) else if (rightChild->keys.size() >= t) { // 找到后继(右子树最左边元素) Node* cur = rightChild; while (!cur->isLeaf) cur = cur->children.front(); T succ = cur->keys.front(); // 用后继替换当前 key node->keys[idx] = succ; // 递归去右子树删掉后继 self(self, rightChild, succ); } // ③ 左右子树都只有 t-1 个关键字,无法借 → 合并 else { // 把 key 下沉到左子树 leftChild->keys.push_back(node->keys[idx]); // 把右子树的 keys 全部并入左子树 leftChild->keys.insert(leftChild->keys.end(), rightChild->keys.begin(), rightChild->keys.end()); // 如果不是叶子,还要把右子树的 children 并过去 if (!leftChild->isLeaf) { leftChild->children.insert(leftChild->children.end(), rightChild->children.begin(), rightChild->children.end()); } // 删除父节点中的 key 和右子树指针 node->keys.erase(node->keys.begin() + idx); node->children.erase(node->children.begin() + idx + 1); delete rightChild; // 继续在合并后的左子树中删除 key self(self, leftChild, key); } } } // ============================================================== // 情况 2:key 不在当前节点 → 去子树里找 // ============================================================== else { if (node->isLeaf) return; // 到叶子还没找到,说明树里没有,直接返回 bool flag = (idx == node->keys.size()); // key 比所有节点都大 → 在最后一个孩子 Node* child = node->children[idx]; // ---------------------------------------------------------- // 删除之前要保证 child 至少有 t 个关键字(否则可能删完不合法) // ---------------------------------------------------------- if (child->keys.size() < t) { Node* leftSibling = (idx > 0 ? node->children[idx - 1] : nullptr); Node* rightSibling = (idx < node->keys.size() ? node->children[idx + 1] : nullptr); // ① 如果左兄弟存在且有 >= t 个关键字 → 向左兄弟借 if (leftSibling && leftSibling->keys.size() >= t) { // 父节点下移一个 key 给 child child->keys.insert(child->keys.begin(), node->keys[idx - 1]); // 左兄弟最后一个 key 上移到父节点 node->keys[idx - 1] = leftSibling->keys.back(); leftSibling->keys.pop_back(); // 如果有子节点,别忘了调整 children if (!leftSibling->isLeaf) { child->children.insert(child->children.begin(), leftSibling->children.back()); leftSibling->children.pop_back(); } } // ② 如果右兄弟存在且有 >= t 个关键字 → 向右兄弟借 else if (rightSibling && rightSibling->keys.size() >= t) { // 父节点下移一个 key 给 child child->keys.push_back(node->keys[idx]); // 右兄弟第一个 key 上移到父节点 node->keys[idx] = rightSibling->keys.front(); rightSibling->keys.erase(rightSibling->keys.begin()); // 如果有子节点,别忘了调整 children if (!rightSibling->isLeaf) { child->children.push_back(rightSibling->children.front()); rightSibling->children.erase(rightSibling->children.begin()); } } // ③ 左右兄弟都不足 t → 合并 else { if (leftSibling) { // 把父节点一个 key 下移到左兄弟 leftSibling->keys.push_back(node->keys[idx - 1]); // 把 child 的 keys 全部并到左兄弟 leftSibling->keys.insert(leftSibling->keys.end(), child->keys.begin(), child->keys.end()); if (!child->isLeaf) { leftSibling->children.insert(leftSibling->children.end(), child->children.begin(), child->children.end()); } // 父节点删除 key 和 child 指针 node->keys.erase(node->keys.begin() + idx - 1); node->children.erase(node->children.begin() + idx); delete child; child = leftSibling; } else if (rightSibling) { // 把父节点一个 key 下移到 child child->keys.push_back(node->keys[idx]); // 把右兄弟的 keys 全部并入 child child->keys.insert(child->keys.end(), rightSibling->keys.begin(), rightSibling->keys.end()); if (!rightSibling->isLeaf) { child->children.insert(child->children.end(), rightSibling->children.begin(), rightSibling->children.end()); } node->keys.erase(node->keys.begin() + idx); node->children.erase(node->children.begin() + idx + 1); delete rightSibling; } } } // ---------------------------------------------------------- // 保证 child 至少有 t 个 key 后,递归下去 // ---------------------------------------------------------- if (flag && idx > node->keys.size()) self(self, node->children[idx - 1], key); else self(self, node->children[idx], key); } }; // 调用删除逻辑 remove(remove, root, _key); // ============================================================== // 删除后可能导致根节点为空 // 需要调整:如果 root 没有 key 了 // ============================================================== if (root->keys.empty()) { Node* oldRoot = root; // 如果 root 是叶子 → 整棵树为空 if (root->isLeaf) root = nullptr; else root = root->children[0]; // root 的唯一孩子成为新的根 delete oldRoot; } }