diff --git a/BinaryTree/BalanceTree/B-Tree/B-Tree-By-AI.h b/BinaryTree/BalanceTree/B-Tree/B-Tree-By-AI.h new file mode 100644 index 0000000..46fcb97 --- /dev/null +++ b/BinaryTree/BalanceTree/B-Tree/B-Tree-By-AI.h @@ -0,0 +1,241 @@ +#include +#include +using namespace std; + +template +struct Node { + bool leaf; // 是否为叶子节点 + vector keys; // 存储关键字 + vector children; // 孩子节点指针 + + Node(bool _leaf) : leaf(_leaf) {} +}; + +template +class BTree { +public: + BTree(int _t) : t(_t), root(nullptr) {} + + void insert(const T& key); // 插入关键字 + void remove(const T& key); // 删除关键字 + void traverse() { traverse(root); cout << endl; } // 中序遍历 + +private: + Node* root; + int t; // 最小度数 + + // ----------- 插入相关辅助函数 ----------- + void insertNonFull(Node* node, const T& key); // 在非满节点插入 + void splitChild(Node* parent, int idx); // 分裂子节点 + + // ----------- 删除相关辅助函数 ----------- + void remove(Node* node, const T& key); // 递归删除 + void removeFromLeaf(Node* node, int idx); // 从叶子节点删除 + void removeFromNonLeaf(Node* node, int idx); // 从非叶子节点删除 + T getPredecessor(Node* node, int idx); // 找前驱 + T getSuccessor(Node* node, int idx); // 找后继 + void fill(Node* node, int idx); // 保证孩子节点至少 t-1 个关键字 + void borrowFromPrev(Node* node, int idx); // 从左兄弟借一个关键字 + void borrowFromNext(Node* node, int idx); // 从右兄弟借一个关键字 + void merge(Node* node, int idx); // 与右兄弟合并 + + // ----------- 遍历辅助函数 ----------- + void traverse(Node* node); +}; + +// ---------------------- 插入相关 ---------------------- +template +void BTree::insert(const T& key) { + if (!root) { // 树空 + root = new Node(true); + root->keys.push_back(key); + } else { + // 根节点满,先分裂根节点 + if (root->keys.size() == 2*t - 1) { + Node* s = new Node(false); + s->children.push_back(root); + splitChild(s, 0); + root = s; + } + insertNonFull(root, key); // 插入非满节点 + } +} + +template +void BTree::insertNonFull(Node* node, const T& key) { + int i = node->keys.size() - 1; + if (node->leaf) { // 叶子节点直接插入 + 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++; + if (node->children[i]->keys.size() == 2*t-1) { + splitChild(node, i); // 分裂满子节点 + if (node->keys[i] < key) i++; + } + insertNonFull(node->children[i], key); + } +} + +template +void BTree::splitChild(Node* parent, int idx) { + Node* y = parent->children[idx]; + Node* z = new Node(y->leaf); + + // 把 y 的后 t-1 个关键字移动到 z + for (int j = 0; j < t-1; j++) z->keys.push_back(y->keys[j+t]); + if (!y->leaf) { + for (int j = 0; j < t; j++) z->children.push_back(y->children[j+t]); + y->children.resize(t); + } + + y->keys.resize(t-1); // 保留前 t-1 个关键字 + parent->children.insert(parent->children.begin()+idx+1, z); + parent->keys.insert(parent->keys.begin()+idx, y->keys[t-1]); // 中间关键字上移 +} + +// ---------------------- 删除相关 ---------------------- +template +void BTree::remove(const T& key) { + if (!root) return; + remove(root, key); + // 如果根节点被删除后没有关键字,调整 root + if (root->keys.empty()) { + Node* oldRoot = root; + if (root->leaf) root = nullptr; + else root = root->children[0]; + delete oldRoot; + } +} + +template +void BTree::remove(Node* node, const T& key) { + int idx = 0; + while (idx < node->keys.size() && node->keys[idx] < key) idx++; + + if (idx < node->keys.size() && node->keys[idx] == key) { + if (node->leaf) removeFromLeaf(node, idx); // 情况1: 叶子节点直接删除 + else removeFromNonLeaf(node, idx); // 情况2: 内部节点 + } else { + if (node->leaf) return; // key不存在 + bool flag = (idx == node->keys.size()); + // 如果孩子节点关键字不足 t 个,需要调整 + if (node->children[idx]->keys.size() < t) fill(node, idx); + if (flag && idx > node->keys.size()) remove(node->children[idx-1], key); + else remove(node->children[idx], key); + } +} + +template +void BTree::removeFromLeaf(Node* node, int idx) { + // 叶子节点直接删除关键字 + node->keys.erase(node->keys.begin() + idx); +} + +template +void BTree::removeFromNonLeaf(Node* node, int idx) { + T k = node->keys[idx]; + // 如果左孩子关键字 >= t,用前驱替换 + if (node->children[idx]->keys.size() >= t) { + T pred = getPredecessor(node, idx); + node->keys[idx] = pred; + remove(node->children[idx], pred); + } + // 如果右孩子关键字 >= t,用后继替换 + else if (node->children[idx+1]->keys.size() >= t) { + T succ = getSuccessor(node, idx); + node->keys[idx] = succ; + remove(node->children[idx+1], succ); + } + // 左右孩子都不足 t,则合并孩子 + else { + merge(node, idx); + remove(node->children[idx], k); + } +} + +template +T BTree::getPredecessor(Node* node, int idx) { + Node* cur = node->children[idx]; + while (!cur->leaf) cur = cur->children.back(); + return cur->keys.back(); +} + +template +T BTree::getSuccessor(Node* node, int idx) { + Node* cur = node->children[idx+1]; + while (!cur->leaf) cur = cur->children[0]; + return cur->keys[0]; +} + +template +void BTree::fill(Node* node, int idx) { + // 尝试从兄弟借关键字,如果不够则合并 + if (idx != 0 && node->children[idx-1]->keys.size() >= t) + borrowFromPrev(node, idx); + else if (idx != node->keys.size() && node->children[idx+1]->keys.size() >= t) + borrowFromNext(node, idx); + else { + if (idx != node->keys.size()) merge(node, idx); + else merge(node, idx-1); + } +} + +template +void BTree::borrowFromPrev(Node* node, int idx) { + Node* child = node->children[idx]; + Node* sibling = node->children[idx-1]; + + // 将父节点关键字下移到 child 前面 + child->keys.insert(child->keys.begin(), node->keys[idx-1]); + if (!child->leaf) child->children.insert(child->children.begin(), sibling->children.back()); + node->keys[idx-1] = sibling->keys.back(); + sibling->keys.pop_back(); + if (!sibling->leaf) sibling->children.pop_back(); +} + +template +void BTree::borrowFromNext(Node* node, int idx) { + Node* child = node->children[idx]; + Node* sibling = node->children[idx+1]; + + // 将父节点关键字下移到 child 后面 + child->keys.push_back(node->keys[idx]); + if (!child->leaf) child->children.push_back(sibling->children[0]); + node->keys[idx] = sibling->keys[0]; + sibling->keys.erase(sibling->keys.begin()); + if (!sibling->leaf) sibling->children.erase(sibling->children.begin()); +} + +template +void BTree::merge(Node* node, int idx) { + Node* child = node->children[idx]; + Node* sibling = node->children[idx+1]; + + // 将父节点关键字和 sibling 的关键字都移入 child + child->keys.push_back(node->keys[idx]); + child->keys.insert(child->keys.end(), sibling->keys.begin(), sibling->keys.end()); + if (!child->leaf) child->children.insert(child->children.end(), sibling->children.begin(), sibling->children.end()); + + // 删除父节点中的关键字和 sibling 指针 + node->keys.erase(node->keys.begin() + idx); + node->children.erase(node->children.begin() + idx + 1); + delete sibling; +} + +// ---------------------- 遍历 ---------------------- +template +void BTree::traverse(Node* node) { + if (!node) return; + int i; + for (i = 0; i < node->keys.size(); i++) { + if (!node->leaf) traverse(node->children[i]); + cout << node->keys[i] << " "; + } + if (!node->leaf) traverse(node->children[i]); +} diff --git a/BinaryTree/BalanceTree/B-Tree/BTree.h b/BinaryTree/BalanceTree/B-Tree/BTree.h index c3444f4..b02af60 100644 --- a/BinaryTree/BalanceTree/B-Tree/BTree.h +++ b/BinaryTree/BalanceTree/B-Tree/BTree.h @@ -131,5 +131,169 @@ inline bool BTree::search(Node* _node, const T& _key) template inline void BTree::erase(const T& _key) { - //1-ɾҶ + 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++; + + // ============================================================== + // 1key ڵǰڵ 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); + } + } + } + // ============================================================== + // 2key ڵǰڵ ȥ + // ============================================================== + 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; + } } + diff --git a/BinaryTree/BalanceTree/B-Tree/main.cpp b/BinaryTree/BalanceTree/B-Tree/main.cpp index 332ea3d..bdfbb3b 100644 --- a/BinaryTree/BalanceTree/B-Tree/main.cpp +++ b/BinaryTree/BalanceTree/B-Tree/main.cpp @@ -16,6 +16,10 @@ int main() { a.insert(11);a.display(); a.insert(15);a.display(); a.insert(17);a.display(); + + a.erase(7);a.display(); + a.erase(10);a.display(); + a.erase(1);a.display(); return 0; } /* @@ -70,4 +74,28 @@ int main() { 6 7 8 9 10 11 15 17 + + +1 2 +3 4 5 + +6 8 +9 10 +11 15 17 + + +1 2 +3 4 5 + +6 8 +9 11 +15 17 + + +2 +3 4 5 +6 8 + +9 11 +15 17 */ \ No newline at end of file