Created
June 5, 2026 13:07
-
-
Save z0z0r4/fe3b97b6e83a8c3259a54e06c725c702 to your computer and use it in GitHub Desktop.
B Tree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <vector> | |
| #include <algorithm> | |
| #include <unordered_set> | |
| #include "btree.h" | |
| auto Node::FindExactKeyIdx(KeyType key, int *idx) -> bool { | |
| int i = 0; | |
| while (i < num_keys_) { | |
| if (keys_[i] == key) { | |
| *idx = i; | |
| return true; | |
| } | |
| i++; | |
| } | |
| return false; | |
| } | |
| auto Node::FindKeyIdx(KeyType key) -> int { | |
| int i = 0; | |
| while (i < num_keys_ && key > keys_[i]) { | |
| i++; | |
| } | |
| return i; | |
| } | |
| void Node::RemoveKVAt(int idx) { | |
| // 将 idx 之后的 Key 和 Value 往前挪一格,覆盖掉原有的 | |
| for (int i = idx; i < GetNumKeys() - 1; ++i) { | |
| SetKey(i, GetKey(i + 1)); | |
| SetValue(i, GetValue(i + 1)); | |
| } | |
| DecrementNumKeys(); | |
| } | |
| auto BTree::Search(const KeyType key, ValueType *value) -> bool { | |
| if (root_page_id_ == INVALID_PAGE_ID) { | |
| return false; | |
| } | |
| auto current_page = disk_manager_.GetPage(root_page_id_); | |
| while (true) { | |
| auto current_node = current_page->GetAs(); | |
| // 是否为叶子节点 | |
| if (current_node->IsLeaf()) { | |
| int idx; | |
| auto result = current_node->FindExactKeyIdx(key, &idx); | |
| if (result) { | |
| *value = current_node->GetValue(idx); | |
| } | |
| return result; | |
| } | |
| // 是内部节点 | |
| auto idx = current_node->FindKeyIdx(key); | |
| // 检查 idx 是否刚好就是 key | |
| if (idx < current_node->GetNumKeys() && current_node->GetKey(idx) == key) { | |
| *value = current_node->GetValue(idx); | |
| return true; | |
| } | |
| // 不是 key,则获取子节点 | |
| auto child_page_id = current_node->GetChild(idx); | |
| current_page = disk_manager_.GetPage(child_page_id); | |
| } | |
| } | |
| auto Node::InsertKeyValue(KeyType key, ValueType value, page_id_t child_page_id) -> bool { | |
| auto idx = FindKeyIdx(key); | |
| // 移动 child | |
| for (int i = GetNumKeys(); i > idx; --i) { | |
| SetChild(i + 1, GetChild(i)); | |
| } | |
| // 移动 kv | |
| for (int i = GetNumKeys() - 1; i >= idx; --i) { | |
| SetKey(i + 1, GetKey(i)); | |
| SetValue(i + 1, GetValue(i)); | |
| } | |
| SetKey(idx, key); | |
| SetValue(idx, value); | |
| if (!IsLeaf() && child_page_id != INVALID_PAGE_ID) { | |
| SetChild(idx + 1, child_page_id); // 应该是插入到右侧子指针 | |
| } | |
| IncrementNumKeys(); | |
| return true; | |
| } | |
| auto BTree::Insert(KeyType key, ValueType value) -> bool { | |
| if (root_page_id_ == INVALID_PAGE_ID) { | |
| auto new_root_page_id = disk_manager_.GetNewPage(true); | |
| root_page_id_ = new_root_page_id; | |
| auto root_page = disk_manager_.GetPage(root_page_id_); | |
| auto root_node = root_page->GetMutAs(); | |
| root_node->InsertKeyValue(key, value); | |
| return true; | |
| } | |
| auto current_page = disk_manager_.GetPage(root_page_id_); | |
| Node *parent_node = nullptr; | |
| while (true) { | |
| auto current_node = current_page->GetAs(); | |
| if (current_node->IsFull()) { | |
| if (current_node->IsLeaf()) { | |
| auto new_page_id = disk_manager_.GetNewPage(true); | |
| auto new_page = disk_manager_.GetPage(new_page_id); | |
| auto new_node = new_page->GetMutAs(); | |
| // split | |
| std::vector<std::pair<KeyType, ValueType> > tmp_kv; | |
| auto count = current_node->GetNumKeys() - MIN_KEY_NUM; | |
| while (count--) { | |
| tmp_kv.push_back({ | |
| current_node->GetKey(current_node->GetNumKeys() - 1), | |
| current_node->GetValue(current_node->GetNumKeys() - 1) | |
| }); | |
| current_node->DecrementNumKeys(); | |
| } | |
| // 反转 tmp_kv | |
| std::reverse(tmp_kv.begin(), tmp_kv.end()); | |
| // 第一个 kv 作为新页的分隔 kv | |
| auto [separator_key, separator_value] = tmp_kv[0]; | |
| for (auto i = 1; i < tmp_kv.size(); ++i) { | |
| auto [k, v] = tmp_kv[i]; | |
| new_node->SetKey(new_node->GetNumKeys(), k); | |
| new_node->SetValue(new_node->GetNumKeys(), v); | |
| new_node->IncrementNumKeys(); | |
| } | |
| if (parent_node == nullptr) { | |
| // 是根节点,创建新内部节点,高度 +1 | |
| auto new_root_page_id = disk_manager_.GetNewPage(false); | |
| auto new_root_page = disk_manager_.GetPage(new_root_page_id); | |
| auto new_root_node = new_root_page->GetMutAs(); | |
| new_root_node->SetKey(0, separator_key); | |
| new_root_node->SetValue(0, separator_value); | |
| new_root_node->SetChild(0, current_page->GetPageId()); | |
| new_root_node->SetChild(1, new_page_id); | |
| new_root_node->IncrementNumKeys(); | |
| root_page_id_ = new_root_page_id; | |
| parent_node = new_root_node; | |
| } else { | |
| parent_node->InsertKeyValue(separator_key, separator_value, new_page_id); | |
| } | |
| if (separator_key == key) { | |
| int idx; | |
| parent_node->FindExactKeyIdx(key, &idx); | |
| parent_node->SetValue(idx, value); | |
| return true; | |
| } | |
| if (separator_key < key) { | |
| current_node = new_node; | |
| } | |
| } else { | |
| auto new_page_id = disk_manager_.GetNewPage(false); | |
| auto new_page = disk_manager_.GetPage(new_page_id); | |
| auto new_node = new_page->GetMutAs(); | |
| // split | |
| std::vector<std::pair<KeyType, ValueType> > tmp_kv; | |
| std::vector<page_id_t> tmp_child_page_ids; | |
| auto count = current_node->GetNumKeys() - MIN_KEY_NUM; | |
| while (count--) { | |
| auto num_keys = current_node->GetNumKeys(); | |
| tmp_kv.push_back({current_node->GetKey(num_keys - 1), current_node->GetValue(num_keys - 1)}); | |
| tmp_child_page_ids.push_back(current_node->GetChild(num_keys)); | |
| current_node->DecrementNumKeys(); | |
| } | |
| // 不需要额外取,因为 tmp_kv[0] 是放入 parent_node 的 | |
| // // 额外取一个 child | |
| // tmp_child_page_ids.push_back(current_node->GetChild(current_node->GetNumKeys())); | |
| std::reverse(tmp_kv.begin(), tmp_kv.end()); | |
| std::reverse(tmp_child_page_ids.begin(), tmp_child_page_ids.end()); | |
| auto [separator_key, separator_value] = tmp_kv[0]; | |
| for (auto i = 1; i < tmp_kv.size(); ++i) { | |
| auto [k, v] = tmp_kv[i]; | |
| new_node->SetKey(new_node->GetNumKeys(), k); | |
| new_node->SetValue(new_node->GetNumKeys(), v); | |
| new_node->IncrementNumKeys(); | |
| } | |
| // 放入 child | |
| for (auto i = 0; i < tmp_child_page_ids.size(); ++i) { | |
| new_node->SetChild(i, tmp_child_page_ids[i]); | |
| } | |
| if (parent_node == nullptr) { | |
| // 是根节点,创建新内部节点,高度 +1 | |
| auto new_root_page_id = disk_manager_.GetNewPage(false); | |
| auto new_root_page = disk_manager_.GetPage(new_root_page_id); | |
| auto new_root_node = new_root_page->GetMutAs(); | |
| new_root_node->SetKey(0, separator_key); | |
| new_root_node->SetValue(0, separator_value); | |
| new_root_node->SetChild(0, current_page->GetPageId()); | |
| new_root_node->SetChild(1, new_page_id); | |
| new_root_node->IncrementNumKeys(); | |
| root_page_id_ = new_root_page_id; | |
| parent_node = new_root_node; | |
| } else { | |
| parent_node->InsertKeyValue(separator_key, separator_value, new_page_id); | |
| } | |
| if (separator_key == key) { | |
| int idx; | |
| parent_node->FindExactKeyIdx(key, &idx); | |
| parent_node->SetValue(idx, value); | |
| return true; | |
| } | |
| if (separator_key < key) { | |
| current_node = new_node; | |
| } | |
| } | |
| } | |
| // 是否为叶子节点 | |
| if (current_node->IsLeaf()) { | |
| int idx; | |
| auto result = current_node->FindExactKeyIdx(key, &idx); | |
| if (result) { | |
| current_node->SetValue(idx, value); | |
| } else { | |
| // 不存在 key,InsertKeyValue | |
| current_node->InsertKeyValue(key, value); | |
| } | |
| return true; | |
| } | |
| // 是内部节点 | |
| auto idx = current_node->FindKeyIdx(key); | |
| // 检查 idx 是否刚好就是 key | |
| if (idx < current_node->GetNumKeys() && current_node->GetKey(idx) == key) { | |
| current_node->SetValue(idx, value); | |
| return true; | |
| } | |
| // 不是 key,则获取子节点 | |
| auto child_page_id = current_node->GetChild(idx); | |
| parent_node = current_node; | |
| current_page = disk_manager_.GetPage(child_page_id); | |
| } | |
| } | |
| auto BTree::Remove(KeyType key) -> bool { | |
| if (root_page_id_ == INVALID_PAGE_ID) { | |
| return false; // 树为空 | |
| } | |
| bool result = RemoveInternal(root_page_id_, key); | |
| // 根节点为空,唯一子节点成为根节点 | |
| auto root_page = disk_manager_.GetPage(root_page_id_); | |
| auto root_node = root_page->GetMutAs(); | |
| if (result && root_node->GetNumKeys() == 0) { | |
| if (root_node->IsLeaf()) { | |
| // 树全空 | |
| root_page_id_ = INVALID_PAGE_ID; | |
| } else { | |
| root_page_id_ = root_node->GetChild(0); | |
| } | |
| } | |
| return result; | |
| } | |
| auto BTree::RemoveInternal(page_id_t page_id, KeyType key) -> bool { | |
| auto page = disk_manager_.GetPage(page_id); | |
| auto node = page->GetMutAs(); | |
| int idx = node->FindKeyIdx(key); | |
| // Key 存在于当前节点 node 中 | |
| if (idx < node->GetNumKeys() && node->GetKey(idx) == key) { | |
| // [1]:如果是叶子节点,直接删除 | |
| if (node->IsLeaf()) { | |
| node->RemoveKVAt(idx); | |
| return true; | |
| } | |
| // [2]:如果是内部节点 | |
| page_id_t left_child_id = node->GetChild(idx); | |
| page_id_t right_child_id = node->GetChild(idx + 1); | |
| auto left_child = disk_manager_.GetPage(left_child_id)->GetMutAs(); | |
| auto right_child = disk_manager_.GetPage(right_child_id)->GetMutAs(); | |
| // [2a]:左子节点有多余 key,可以是借用 | |
| if (left_child->GetNumKeys() >= MIN_DEGREE) { | |
| auto pred = GetPredecessor(left_child_id); // 找前驱 | |
| node->SetKey(idx, pred.first); | |
| node->SetValue(idx, pred.second); | |
| return RemoveInternal(left_child_id, pred.first); // | |
| } | |
| // [2b]:右子节点有多余 key,借用 | |
| if (right_child->GetNumKeys() >= MIN_DEGREE) { | |
| auto succ = GetSuccessor(right_child_id); // 找后继 | |
| node->SetKey(idx, succ.first); | |
| node->SetValue(idx, succ.second); | |
| return RemoveInternal(right_child_id, succ.first); | |
| } | |
| // [2c]:左右孩子都只有 t-1 个 key,执行合并 | |
| Merge(node, idx); // 将 key 和 right_child 合并进 left_child | |
| return RemoveInternal(left_child_id, key); // 在合并后的左孩子中继续递归删除 key | |
| } | |
| // Key 当前不在内部节点 node 中 | |
| if (node->IsLeaf()) { | |
| return false; // 不存在 | |
| } | |
| // 找到包含 key 的子节点 | |
| bool is_last_child = (idx == node->GetNumKeys()); | |
| page_id_t child_id = node->GetChild(idx); | |
| auto child = disk_manager_.GetPage(child_id)->GetMutAs(); | |
| // 子节点只有 t-1 个 key,执行 3a 或 3b 填充它 | |
| if (child->GetNumKeys() < MIN_DEGREE) { | |
| FillChild(node, idx); | |
| } | |
| // 如何合并后 idx 变了 | |
| if (is_last_child && idx > node->GetNumKeys()) { | |
| return RemoveInternal(node->GetChild(idx - 1), key); | |
| } | |
| return RemoveInternal(node->GetChild(idx), key); | |
| } | |
| auto BTree::GetPredecessor(page_id_t page_id) -> std::pair<KeyType, ValueType> { | |
| auto curr = disk_manager_.GetPage(page_id)->GetAs(); | |
| // 一直往最右侧子节点走,直到叶子 | |
| while (!curr->IsLeaf()) { | |
| curr = disk_manager_.GetPage(curr->GetChild(curr->GetNumKeys()))->GetAs(); | |
| } | |
| return {curr->GetKey(curr->GetNumKeys() - 1), curr->GetValue(curr->GetNumKeys() - 1)}; | |
| } | |
| auto BTree::GetSuccessor(page_id_t page_id) -> std::pair<KeyType, ValueType> { | |
| auto curr = disk_manager_.GetPage(page_id)->GetAs(); | |
| // 一直往最左侧子节点走,直到叶子 | |
| while (!curr->IsLeaf()) { | |
| curr = disk_manager_.GetPage(curr->GetChild(0))->GetAs(); | |
| } | |
| return {curr->GetKey(0), curr->GetValue(0)}; | |
| } | |
| // 确保子节点至少有 t 个 key | |
| void BTree::FillChild(Node *parent, int child_idx) { | |
| page_id_t prev_id = (child_idx > 0) ? parent->GetChild(child_idx - 1) : INVALID_PAGE_ID; | |
| page_id_t next_id = (child_idx < parent->GetNumKeys()) ? parent->GetChild(child_idx + 1) : INVALID_PAGE_ID; | |
| Node *prev_child = (prev_id != INVALID_PAGE_ID) ? disk_manager_.GetPage(prev_id)->GetMutAs() : nullptr; | |
| Node *next_child = (next_id != INVALID_PAGE_ID) ? disk_manager_.GetPage(next_id)->GetMutAs() : nullptr; | |
| // [3a]:左兄弟至少有 t 个,向左借 | |
| if (prev_child && prev_child->GetNumKeys() >= MIN_DEGREE) { | |
| BorrowFromPrev(parent, child_idx); | |
| } | |
| // [3a]:右兄弟至少有 t 个,向右借 | |
| else if (next_child && next_child->GetNumKeys() >= MIN_DEGREE) { | |
| BorrowFromNext(parent, child_idx); | |
| } | |
| // [3b]:都是 t - 1 则左或者右合并 | |
| else { | |
| if (child_idx != parent->GetNumKeys()) { | |
| Merge(parent, child_idx); // 如果不是最右孩子,与后一个合并 | |
| } else { | |
| Merge(parent, child_idx - 1); // 如果是最右孩子,与前一个合并 | |
| } | |
| } | |
| } | |
| // 从左兄弟借用一个 | |
| void BTree::BorrowFromPrev(Node *parent, int child_idx) { | |
| auto child = disk_manager_.GetPage(parent->GetChild(child_idx))->GetMutAs(); | |
| auto sibling = disk_manager_.GetPage(parent->GetChild(child_idx - 1))->GetMutAs(); | |
| // 将 child 中的所有元素往后挪一格,在头部腾出空间 | |
| for (int i = child->GetNumKeys(); i > 0; --i) { | |
| child->SetKey(i, child->GetKey(i - 1)); | |
| child->SetValue(i, child->GetValue(i - 1)); | |
| } | |
| if (!child->IsLeaf()) { | |
| for (int i = child->GetNumKeys() + 1; i > 0; --i) { | |
| child->SetChild(i, child->GetChild(i - 1)); | |
| } | |
| } | |
| // 将父节点的 key 放入 child 的头部 | |
| child->SetKey(0, parent->GetKey(child_idx - 1)); | |
| child->SetValue(0, parent->GetValue(child_idx - 1)); | |
| if (!child->IsLeaf()) { | |
| child->SetChild(0, sibling->GetChild(sibling->GetNumKeys())); | |
| } | |
| child->IncrementNumKeys(); | |
| // 将左兄弟的最后一个 key 放入父节点,填补之前下移的空位 | |
| parent->SetKey(child_idx - 1, sibling->GetKey(sibling->GetNumKeys() - 1)); | |
| parent->SetValue(child_idx - 1, sibling->GetValue(sibling->GetNumKeys() - 1)); | |
| sibling->DecrementNumKeys(); | |
| } | |
| // 从右兄弟借用一个 | |
| void BTree::BorrowFromNext(Node *parent, int child_idx) { | |
| auto child = disk_manager_.GetPage(parent->GetChild(child_idx))->GetMutAs(); | |
| auto right_sibling = disk_manager_.GetPage(parent->GetChild(child_idx + 1))->GetMutAs(); | |
| // 将父节点的 key 放入 child 的尾部 | |
| child->SetKey(child->GetNumKeys(), parent->GetKey(child_idx)); | |
| child->SetValue(child->GetNumKeys(), parent->GetValue(child_idx)); | |
| if (!child->IsLeaf()) { | |
| child->SetChild(child->GetNumKeys() + 1, right_sibling->GetChild(0)); | |
| } | |
| child->IncrementNumKeys(); | |
| // 将右兄弟的第一个 key 放回父节点 | |
| parent->SetKey(child_idx, right_sibling->GetKey(0)); | |
| parent->SetValue(child_idx, right_sibling->GetValue(0)); | |
| // 右兄弟全部前移一个索引,填补回去 | |
| for (int i = 0; i < right_sibling->GetNumKeys() - 1; ++i) { | |
| right_sibling->SetKey(i, right_sibling->GetKey(i + 1)); | |
| right_sibling->SetValue(i, right_sibling->GetValue(i + 1)); | |
| } | |
| if (!right_sibling->IsLeaf()) { | |
| for (int i = 0; i < right_sibling->GetNumKeys(); ++i) { | |
| // child 比 key 数组长 1 | |
| right_sibling->SetChild(i, right_sibling->GetChild(i + 1)); | |
| } | |
| } | |
| right_sibling->DecrementNumKeys(); | |
| } | |
| void BTree::Merge(Node *parent, int child_idx) { | |
| auto left_child = disk_manager_.GetPage(parent->GetChild(child_idx))->GetMutAs(); | |
| auto right_child = disk_manager_.GetPage(parent->GetChild(child_idx + 1))->GetMutAs(); | |
| // 将 parent 里的下放 key 放到 left_child | |
| left_child->SetKey(MIN_DEGREE - 1, parent->GetKey(child_idx)); | |
| left_child->SetValue(MIN_DEGREE - 1, parent->GetValue(child_idx)); | |
| // 把 right_child 里的所有 key 和 child 移植到 left_child 的后半截 | |
| for (int i = 0; i < right_child->GetNumKeys(); ++i) { | |
| left_child->SetKey(i + MIN_DEGREE, right_child->GetKey(i)); | |
| left_child->SetValue(i + MIN_DEGREE, right_child->GetValue(i)); | |
| } | |
| if (!left_child->IsLeaf()) { | |
| for (int i = 0; i <= right_child->GetNumKeys(); ++i) { | |
| left_child->SetChild(i + MIN_DEGREE, right_child->GetChild(i)); | |
| } | |
| } | |
| // left_child 现在直接满员 | |
| left_child->SetNumKeys(MAX_KEY_NUM); | |
| // 删掉 parent 中的分隔 key | |
| for (int i = child_idx; i < parent->GetNumKeys() - 1; ++i) { | |
| parent->SetKey(i, parent->GetKey(i + 1)); | |
| parent->SetValue(i, parent->GetValue(i + 1)); | |
| } | |
| for (int i = child_idx + 1; i < parent->GetNumKeys(); ++i) { | |
| parent->SetChild(i, parent->GetChild(i + 1)); | |
| } | |
| parent->DecrementNumKeys(); | |
| } | |
| int main() { | |
| BTree btree; | |
| btree.Insert(1, 1); | |
| ValueType val; | |
| btree.Search(1, &val); | |
| btree.Remove(1); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <cstdint> | |
| #include <iostream> | |
| #include <utility> | |
| #include <vector> | |
| #include <memory> | |
| #define INVALID_PAGE_ID (-1) | |
| #define MIN_DEGREE 2 | |
| #define MAX_KEY_NUM (MIN_DEGREE * 2 - 1) | |
| #define MIN_KEY_NUM (MIN_DEGREE - 1) | |
| #define MAX_CHILD_NUM (MIN_DEGREE * 2) | |
| #define MIN_CHILD_NUM MIN_DEGREE | |
| using page_id_t = uint32_t; | |
| using KeyType = uint32_t; | |
| using ValueType = uint32_t; | |
| class Node { | |
| public: | |
| explicit Node(const bool is_leaf) : isLeaf_(is_leaf), num_keys_(0) { | |
| keys_.resize(MAX_KEY_NUM + 1); | |
| values_.resize(MAX_KEY_NUM + 1); | |
| children_page_id_.resize(MAX_CHILD_NUM + 1); | |
| } | |
| auto IsLeaf() const -> bool { return isLeaf_; } | |
| void SetIsLeaf(const bool is_leaf) { isLeaf_ = is_leaf; } | |
| auto IsFull() const -> bool { return num_keys_ >= MAX_KEY_NUM; } | |
| auto FindExactKeyIdx(KeyType key, int *idx) -> bool; | |
| auto FindKeyIdx(KeyType key) -> int; | |
| auto InsertKeyValue(KeyType key, ValueType value, page_id_t child_page_id = INVALID_PAGE_ID) -> bool; | |
| auto GetKey(const int key_idx) const -> KeyType { return keys_[key_idx]; } | |
| void SetKey(const int key_idx, const KeyType key) { keys_[key_idx] = key; } | |
| auto GetValue(const int idx) const -> ValueType { return values_[idx]; } | |
| void SetValue(const int idx, const ValueType value) { values_[idx] = value; } | |
| auto GetChild(const int idx) const -> page_id_t { return children_page_id_[idx]; } | |
| void SetChild(const int idx, const page_id_t child_page_id) { children_page_id_[idx] = child_page_id; } | |
| auto GetNumKeys() const -> int { return num_keys_; } | |
| void SetNumKeys(const int num_keys) { num_keys_ = num_keys; } | |
| void IncrementNumKeys() { num_keys_++; } | |
| void DecrementNumKeys() { num_keys_--; } | |
| void AddKeyValue(KeyType key, ValueType value) { | |
| keys_.push_back(key); | |
| values_.push_back(value); | |
| num_keys_++; | |
| } | |
| void AddKey(KeyType key) { | |
| keys_.push_back(key); | |
| num_keys_++; | |
| } | |
| void AddChild(page_id_t child_page_id) { | |
| children_page_id_.push_back(child_page_id); | |
| } | |
| void ResizeKeys(int size) { | |
| keys_.resize(size); | |
| } | |
| void ResizeValues(int size) { | |
| values_.resize(size); | |
| } | |
| void ResizeChildren(int size) { | |
| children_page_id_.resize(size); | |
| } | |
| void RemoveKVAt(int idx); | |
| private: | |
| bool isLeaf_; | |
| int num_keys_; | |
| std::vector<KeyType> keys_; | |
| std::vector<page_id_t> children_page_id_; | |
| std::vector<ValueType> values_; | |
| }; | |
| class Page { | |
| public: | |
| Page(const page_id_t page_id, const bool isLeaf) : page_id_(page_id), node_(isLeaf) { | |
| } | |
| auto GetAs() -> Node * { | |
| return &node_; | |
| } | |
| auto GetMutAs() -> Node * { | |
| return &node_; | |
| } | |
| auto GetPageId() const -> page_id_t {return page_id_;} | |
| private: | |
| page_id_t page_id_; | |
| Node node_; | |
| }; | |
| class DiskManager { | |
| public: | |
| DiskManager() : num_pages_(0) { | |
| } | |
| page_id_t GetNewPage(bool isLeaf) { | |
| auto new_page_id = static_cast<page_id_t>(num_pages_++); | |
| pages_.push_back(std::make_unique<Page>(new_page_id, isLeaf)); | |
| return new_page_id; | |
| } | |
| auto GetPage(const page_id_t page_id) -> Page * { | |
| if (page_id >= 0 && page_id < static_cast<page_id_t>(pages_.size())) { | |
| return pages_[page_id].get(); | |
| } | |
| return nullptr; | |
| } | |
| private: | |
| int num_pages_; | |
| std::vector<std::unique_ptr<Page>> pages_; | |
| }; | |
| class BTree { | |
| public: | |
| BTree() : root_page_id_(INVALID_PAGE_ID) { disk_manager_ = DiskManager(); } | |
| BTree(page_id_t root_page_id, DiskManager&& disk_manager) | |
| : root_page_id_(root_page_id), disk_manager_(std::move(disk_manager)) {} | |
| auto Search(KeyType key, ValueType *value) -> bool; | |
| auto Insert(KeyType key, ValueType value) -> bool; | |
| auto Remove(KeyType key) -> bool; | |
| private: | |
| auto RemoveInternal(page_id_t page_id, KeyType key) -> bool; | |
| // 获取前驱和后继 | |
| auto GetPredecessor(page_id_t page_id) -> std::pair<KeyType, ValueType>; | |
| auto GetSuccessor(page_id_t page_id) -> std::pair<KeyType, ValueType>; | |
| void FillChild(Node *parent, int child_idx); | |
| // 3a:向左/右兄弟借 kv | |
| void BorrowFromPrev(Node *parent, int child_idx); | |
| void BorrowFromNext(Node *parent, int child_idx); | |
| // 2c / 3b:合并兄弟节点 | |
| void Merge(Node *parent, int child_idx); | |
| page_id_t root_page_id_; | |
| DiskManager disk_manager_; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment