B树(B-tree)是一种自平衡的树形数据结构,用于存储和管理大量数据。它被广泛应用于文件系统和数据库管理系统中。

B树具有以下几个优点:

  1. 支持快速的查找、插入和删除操作。B树的查询和修改操作的时间复杂度为O(log n),其中n是B树中存储的关键字数量。

  2. B树可以存储大量的数据,因为它可以在节点中存储多个关键字和指向子节点的指针。这使得B树比二叉查找树更加适合存储大规模的数据。

  3. B树的节点大小通常和磁盘块大小相同,因此可以直接在磁盘上存储B树。这种优化可以减少磁盘I/O操作的次数,从而提高查询和修改操作的效率。

  4. B树可以自平衡,这意味着每次插入和删除操作后,B树都可以通过旋转和重构节点来保持平衡。这种自平衡的特性使得B树可以应对动态的数据存储需求,同时保持高效的查询和修改操作。

因此,B树被广泛应用于文件系统、数据库管理系统、存储系统和其他需要高效存储和管理大量数据的应用中。

下面使用c++语言描述一下B树

#include <iostream>
#include <vector>

using namespace std;

const int MAX_CHILDREN_NUM = 4;
const int MIN_CHILDREN_NUM = 2;
const int MAX_KEY_NUM = 3;
const int MIN_KEY_NUM = 1;

struct BTreeNode {
    vector<int> keys;                // 存储关键字的向量
    vector<BTreeNode*> children;    // 存储指向子节点的指针的向量
    BTreeNode* parent;              // 指向父节点的指针
    bool is_leaf;                   // 是否为叶子节点
    int key_num;                    // 关键字数量

    BTreeNode() {
        keys.resize(MAX_KEY_NUM);
        children.resize(MAX_CHILDREN_NUM);
        parent = nullptr;
        is_leaf = false;
        key_num = 0;
    }
};

class BTree {
public:
    BTree();
    ~BTree();

    void insert(int key);   // 插入关键字
    void remove(int key);   // 删除关键字
    bool search(int key);   // 查找关键字

    void print_tree();      // 输出B树的结构

private:
    BTreeNode* root;        // 指向B树根节点的指针

    void split_child(BTreeNode* parent, int pos, BTreeNode* child);  // 分裂子节点
    void merge_child(BTreeNode* parent, int pos, BTreeNode* child);  // 合并子节点
    void borrow_from_left(BTreeNode* parent, int pos, BTreeNode* child);   // 从左兄弟节点中借关键字
    void borrow_from_right(BTreeNode* parent, int pos, BTreeNode* child);  // 从右兄弟节点中借关键字

    void insert_nonfull(BTreeNode* node, int key);  // 在非满节点中插入关键字
    void remove_nonleaf(BTreeNode* node, int key);  // 在非叶子节点中删除关键字
    void remove_leaf(BTreeNode* node, int key);     // 在叶子节点中删除关键字

    BTreeNode* search_node(int key);    // 查找包含关键字的节点
    void print_node(BTreeNode* node);   // 输出节点信息
    void destroy_tree(BTreeNode* node); // 销毁B树
};

BTree::BTree() {
    root = nullptr;
}

BTree::~BTree() {
    destroy_tree(root);
}

void BTree::insert(int key) {
    if (root == nullptr) {
        root = new BTreeNode();
        root->keys[0] = key;
        root->is_leaf = true;
        root->key_num = 1;
    }
    else {
        if (root->key_num == MAX_KEY_NUM) {
            BTreeNode* new_root = new BTreeNode();
            new_root->children[0] = root;
            new_root->parent = nullptr;
            root->parent = new_root;
            split_child(new_root, 0, root);
            root = new_root;
        }
        insert_nonfull(root, key);
    }
}

void BTree::remove(int key) {
    if (root == nullptr) {
        cout << "BTree is empty!" << endl;
        return;
    }
    remove_nonleaf(root, key);
}

bool BTree::search(int key) {
return (search_node(key) != nullptr);
}

void BTree::split_child(BTreeNode* parent, int pos, BTreeNode* child) {
BTreeNode* new_child = new BTreeNode();
new_child->is_leaf = child->is_leaf;
new_child->key_num = MIN_KEY_NUM;
for (int i = 0; i < MIN_KEY_NUM; i++) {
new_child->keys[i] = child->keys[i + MIN_CHILDREN_NUM];
}
if (!child->is_leaf) {
for (int i = 0; i < MIN_CHILDREN_NUM; i++) {
new_child->children[i] = child->children[i + MIN_CHILDREN_NUM];
new_child->children[i]->parent = new_child;
}
}
child->key_num = MIN_KEY_NUM;
for (int i = parent->key_num; i > pos; i--) {
parent->children[i + 1] = parent->children[i];
parent->children[i + 1]->parent = parent;
}
parent->children[pos + 1] = new_child;
new_child->parent = parent;
for (int i = parent->key_num - 1; i >= pos; i--) {
parent->keys[i + 1] = parent->keys[i];
}
parent->keys[pos] = child->keys[MIN_KEY_NUM];
parent->key_num++;
}

void BTree::merge_child(BTreeNode* parent, int pos, BTreeNode* child) {
BTreeNode* left_child = parent->children[pos];
left_child->keys[MIN_KEY_NUM] = parent->keys[pos];
left_child->key_num++;
for (int i = 0; i < MIN_KEY_NUM; i++) {
left_child->keys[MIN_KEY_NUM + 1 + i] = child->keys[i];
left_child->key_num++;
}
if (!child->is_leaf) {
for (int i = 0; i < MIN_CHILDREN_NUM; i++) {
left_child->children[MIN_CHILDREN_NUM + i] = child->children[i];
left_child->children[MIN_CHILDREN_NUM + i]->parent = left_child;
}
}
for (int i = pos; i < parent->key_num - 1; i++) {
parent->keys[i] = parent->keys[i + 1];
parent->children[i + 1] = parent->children[i + 2];
parent->children[i + 1]->parent = parent;
}
parent->key_num--;
delete child;
}

void BTree::borrow_from_left(BTreeNode* parent, int pos, BTreeNode* child) {
BTreeNode* left_child = parent->children[pos - 1];
child->key_num++;
for (int i = child->key_num - 1; i > 0; i--) {
child->keys[i] = child->keys[i - 1];
}
if (!child->is_leaf) {
for (int i = child->key_num; i > 0; i--) {
child->children[i] = child->children[i - 1];
child->children[i]->parent = child;
}
child->children[0] = left_child->children[left_child->key_num];
child->children[0]->parent = child;
}
child->keys[0] = parent->keys[pos - 1];
parent->keys[pos - 1] = left_child->keys[left_child->key_num--;]}
void BTree::borrow_from_right(BTreeNode* parent, int pos, BTreeNode* child) {
BTreeNode* right_child = parent->children[pos + 1];
child->keys[child->key_num] = parent->keys[pos];
child->key_num++;
if (!child->is_leaf) {
child->children[child->key_num] = right_child->children[0];
child->children[child->key_num]->parent = child;
}
parent->keys[pos] = right_child->keys[0];
right_child->key_num--;
for (int i = 0; i < right_child->key_num; i++) {
right_child->keys[i] = right_child->keys[i + 1];
}
if (!right_child->is_leaf) {
for (int i = 0; i < right_child->key_num + 1; i++) {
right_child->children[i] = right_child->children[i + 1];
right_child->children[i]->parent = right_child;
}
}
}

BTreeNode* BTree::insert_node(BTreeNode* node, int key) {
int pos = node->key_num - 1;
if (node->is_leaf) {
while (pos >= 0 && key < node->keys[pos]) {
node->keys[pos + 1] = node->keys[pos];
pos--;
}
node->keys[pos + 1] = key;
node->key_num++;
} else {
while (pos >= 0 && key < node->keys[pos]) {
pos--;
}
pos++;
BTreeNode* child = node->children[pos];
if (child->key_num == MAX_KEY_NUM) {
split_child(node, pos, child);
if (key > node->keys[pos]) {
pos++;
child = node->children[pos];
}
}
insert_node(child, key);
}
return node;
}

void BTree::insert(int key) {
if (root == nullptr) {
root = new BTreeNode();
root->is_leaf = true;
root->keys[0] = key;
root->key_num = 1;
} else {
if (root->key_num == MAX_KEY_NUM) {
BTreeNode* new_root = new BTreeNode();
new_root->is_leaf = false;
new_root->key_num = 0;
new_root->children[0] = root;
root->parent = new_root;
split_child(new_root, 0, root);
insert_node(new_root, key);
root = new_root;
} else {
insert_node(root, key);
}
}
}

BTreeNode* BTree::search_node(int key) {
if (root == nullptr) {
return nullptr;
} else {
BTreeNode* node = root;
while (node != nullptr) {
int pos = 0;
while (pos < node->key_num && key > node->keys[pos]) {
pos++;
}
if (pos < node->key_num && key == node->keys[pos]) {
return node;
}
if (node->is_leaf) {
return nullptr;
} else {
node = node->children[pos];
}
}
return nullptr;
}
}

虽然看上去很复杂,其实学习一下对数据结构会增加认识,也可以提升代码能力。

(只是写出来大致思路,具体还有不是缺点,请见谅)

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐