- #include <stdio.h>
- #include <stdlib.h>
- // 定义 B 树的最小度数(每个节点至少有 t 个孩子,最多有 2t - 1 个键值)
- #define T 3
- // B 树节点结构
- typedef struct BTreeNode {
- int *keys; // 存储键值的数组
- int t; // 最小度数
- struct BTreeNode **C; // 子节点指针数组
- int n; // 当前节点的键值个数
- int leaf; // 是否是叶子节点
- } BTreeNode;
- // 创建一个新的 B 树节点
- BTreeNode *createNode(int t, int leaf) {
- BTreeNode *node = (BTreeNode *)malloc(sizeof(BTreeNode));
- if (!node) {
- fprintf(stderr, "Memory allocation failed for BTreeNode.\n");
- exit(EXIT_FAILURE);
- }
- node->t = t;
- node->leaf = leaf;
- node->keys = (int *)malloc((2 * t - 1) * sizeof(int));
- node->C = (BTreeNode **)malloc(2 * t * sizeof(BTreeNode *));
- node->n = 0;
- if (!node->keys || !node->C) {
- fprintf(stderr, "Memory allocation failed for keys or children.\n");
- exit(EXIT_FAILURE);
- }
- return node;
- }
- // 遍历 B 树(中序遍历)
- void traverse(BTreeNode *root) {
- if (root == NULL) return;
- // 遍历每个键值前的子树
- for (int i = 0; i < root->n; i++) {
- if (!root->leaf) {
- traverse(root->C[i]);
- }
- printf("%d ", root->keys[i]); // 打印键值
- }
- // 遍历最后一个子树
- if (!root->leaf) {
- traverse(root->C[root->n]);
- }
- }
- // 搜索键值
- BTreeNode *search(BTreeNode *root, int k) {
- int i = 0;
- // 在当前节点中查找键值的位置
- while (i < root->n && k > root->keys[i]) {
- i++;
- }
- // 如果找到键值,返回当前节点
- if (i < root->n && root->keys[i] == k) {
- return root;
- }
- // 如果是叶子节点,直接返回 NULL
- if (root->leaf) {
- return NULL;
- }
- // 在对应的子节点递归查找
- return search(root->C[i], k);
- }
- // 分裂子节点 y
- void splitChild(BTreeNode *parent, int i, BTreeNode *y) {
- int t = y->t;
- // 创建新节点 z,存储 y 的后半部分键值和子节点
- BTreeNode *z = createNode(t, y->leaf);
- z->n = t - 1;
- // 将 y 的后半部分键值复制到 z
- for (int j = 0; j < t - 1; j++) {
- z->keys[j] = y->keys[j + t];
- }
- // 如果 y 不是叶子节点,将 y 的后半部分子节点指针复制到 z
- if (!y->leaf) {
- for (int j = 0; j < t; j++) {
- z->C[j] = y->C[j + t];
- }
- }
- y->n = t - 1; // 更新 y 的键值个数
- // 将 z 插入到 parent 的子节点列表中
- for (int j = parent->n; j >= i + 1; j--) {
- parent->C[j + 1] = parent->C[j];
- }
- parent->C[i + 1] = z;
- // 将 y 的中间键提升到 parent
- for (int j = parent->n - 1; j >= i; j--) {
- parent->keys[j + 1] = parent->keys[j];
- }
- parent->keys[i] = y->keys[t - 1];
- parent->n++;
- }
- // 插入到非满节点中
- void insertNonFull(BTreeNode *node, int k) {
- int i = node->n - 1;
- // 如果是叶子节点
- if (node->leaf) {
- // 找到插入位置并移动键值
- while (i >= 0 && k < node->keys[i]) {
- node->keys[i + 1] = node->keys[i];
- i--;
- }
- node->keys[i + 1] = k; // 插入键值
- node->n++;
- } else {
- // 找到子节点的位置
- while (i >= 0 && k < node->keys[i]) {
- i--;
- }
- i++;
- // 如果子节点已满,先分裂子节点
- if (node->C[i]->n == 2 * node->t - 1) {
- splitChild(node, i, node->C[i]);
- // 判断 k 应插入到哪个子节点
- if (k > node->keys[i]) {
- i++;
- }
- }
- insertNonFull(node->C[i], k);
- }
- }
- // 插入键值到 B 树
- void insert(BTreeNode **rootRef, int k, int t) {
- BTreeNode *root = *rootRef;
- // 如果根节点已满
- if (root->n == 2 * t - 1) {
- // 创建新根节点
- BTreeNode *newRoot = createNode(t, 0);
- newRoot->C[0] = root;
- // 分裂旧根节点
- splitChild(newRoot, 0, root);
- // 插入到合适的子节点
- int i = 0;
- if (k > newRoot->keys[0]) {
- i++;
- }
- insertNonFull(newRoot->C[i], k);
- *rootRef = newRoot; // 更新根节点
- } else {
- insertNonFull(root, k);
- }
- }
- // 释放 B 树节点
- void freeBTree(BTreeNode *node) {
- if (node == NULL) return;
- if (!node->leaf) {
- for (int i = 0; i <= node->n; i++) {
- freeBTree(node->C[i]);
- }
- }
- free(node->keys);
- free(node->C);
- free(node);
- }
- // 主函数
- int main() {
- // 创建空 B 树
- BTreeNode *root = createNode(T, 1);
- // 插入一些数据
- insert(&root, 10, T);
- insert(&root, 20, T);
- insert(&root, 5, T);
- insert(&root, 6, T);
- insert(&root, 12, T);
- insert(&root, 30, T);
- insert(&root, 7, T);
- insert(&root, 17, T);
- // 遍历 B 树
- printf("Traversal of the B-Tree:\n");
- traverse(root);
- printf("\n");
- // 搜索键值
- int key = 6;
- printf("Searching for key %d in the B-Tree...\n", key);
- BTreeNode *result = search(root, key);
- if (result != NULL) {
- printf("Key %d found in the B-Tree.\n", key);
- } else {
- printf("Key %d not found in the B-Tree.\n", key);
- }
- // 释放 B 树
- freeBTree(root);
- return 0;
- }
复制代码 C语言b树
- 数据结构:
- 每个节点存储一个 keys 数组和一个 C 子节点指针数组。
- n 表现当前键值数,leaf 表现是否为叶子节点。
- 主要功能:
- 创建节点:createNode 动态分配节点。
- 插入:插入时处理节点分裂,包管 B 树平衡。
- 查找:递归在树中查找键值。
- 遍历:按中序遍历输出键值。
- 释放内存:freeBTree 确保无内存泄漏。
- 加强结实性:
- 内存分配检测:每次动态分配都检查是否乐成。
- 边界条件处理:空树或单节点插入、满节点分裂等情况均已处理。
- #include <iostream>
- #include <vector>
- #include <memory>
- using namespace std;
- // 定义 B 树的最小度数
- const int T = 3; // 每个节点最多 2*T-1 个键,最少 T-1 个键
- // B 树节点类
- class BTreeNode {
- public:
- vector<int> keys; // 键值数组
- vector<shared_ptr<BTreeNode>> children; // 子节点指针数组
- int t; // 最小度数
- bool leaf; // 是否为叶子节点
- // 构造函数
- BTreeNode(int t, bool leaf) : t(t), leaf(leaf) {}
- // 遍历 B 树(中序遍历)
- void traverse() {
- int i;
- // 遍历每个键值前的子树
- for (i = 0; i < keys.size(); i++) {
- if (!leaf) {
- children[i]->traverse();
- }
- cout << keys[i] << " ";
- }
- // 遍历最后一个子树
- if (!leaf) {
- children[i]->traverse();
- }
- }
- // 搜索键值
- shared_ptr<BTreeNode> search(int k) {
- int i = 0;
- // 找到第一个大于或等于 k 的键
- while (i < keys.size() && k > keys[i]) {
- i++;
- }
- // 如果键值等于 k,返回当前节点
- if (i < keys.size() && keys[i] == k) {
- return shared_from_this();
- }
- // 如果是叶子节点,则键值不存在
- if (leaf) {
- return nullptr;
- }
- // 在对应的子节点递归查找
- return children[i]->search(k);
- }
- // 分裂子节点
- void splitChild(int i, shared_ptr<BTreeNode> y) {
- // 创建一个新节点 z,存储 y 的后半部分键值和子节点
- auto z = make_shared<BTreeNode>(y->t, y->leaf);
- z->keys.resize(t - 1);
- for (int j = 0; j < t - 1; j++) {
- z->keys[j] = y->keys[j + t];
- }
- // 如果 y 不是叶子节点,将 y 的后半部分子节点移动到 z
- if (!y->leaf) {
- z->children.resize(t);
- for (int j = 0; j < t; j++) {
- z->children[j] = y->children[j + t];
- }
- }
- // 调整 y 的键值数
- y->keys.resize(t - 1);
- // 在父节点中插入新的子节点 z
- children.insert(children.begin() + i + 1, z);
- // 将 y 的中间键提升到父节点
- keys.insert(keys.begin() + i, y->keys[t - 1]);
- }
- // 插入到非满节点中
- void insertNonFull(int k) {
- int i = keys.size() - 1;
- if (leaf) {
- // 如果是叶子节点,找到插入位置并插入
- while (i >= 0 && k < keys[i]) {
- i--;
- }
- keys.insert(keys.begin() + i + 1, k);
- } else {
- // 找到子节点位置
- while (i >= 0 && k < keys[i]) {
- i--;
- }
- i++;
- // 如果子节点已满,先分裂子节点
- if (children[i]->keys.size() == 2 * t - 1) {
- splitChild(i, children[i]);
- // 判断插入位置
- if (k > keys[i]) {
- i++;
- }
- }
- children[i]->insertNonFull(k);
- }
- }
- };
- // B 树类
- class BTree {
- private:
- shared_ptr<BTreeNode> root; // 根节点
- int t; // 最小度数
- public:
- // 构造函数
- BTree(int t) : t(t), root(nullptr) {}
- // 遍历 B 树
- void traverse() {
- if (root != nullptr) {
- root->traverse();
- }
- }
- // 搜索键值
- shared_ptr<BTreeNode> search(int k) {
- if (root == nullptr) {
- return nullptr;
- } else {
- return root->search(k);
- }
- }
- // 插入键值
- void insert(int k) {
- if (root == nullptr) {
- // 如果根节点为空,创建一个新节点
- root = make_shared<BTreeNode>(t, true);
- root->keys.push_back(k);
- } else {
- // 如果根节点已满
- if (root->keys.size() == 2 * t - 1) {
- // 创建一个新根节点
- auto newRoot = make_shared<BTreeNode>(t, false);
- // 将旧根节点作为新根的子节点
- newRoot->children.push_back(root);
- // 分裂旧根节点
- newRoot->splitChild(0, root);
- // 插入到合适的子节点
- if (k > newRoot->keys[0]) {
- newRoot->children[1]->insertNonFull(k);
- } else {
- newRoot->children[0]->insertNonFull(k);
- }
- root = newRoot; // 更新根节点
- } else {
- root->insertNonFull(k);
- }
- }
- }
- };
- // 主函数
- int main() {
- // 创建 B 树
- BTree tree(T);
- // 插入一些数据
- tree.insert(10);
- tree.insert(20);
- tree.insert(5);
- tree.insert(6);
- tree.insert(12);
- tree.insert(30);
- tree.insert(7);
- tree.insert(17);
- // 遍历 B 树
- cout << "Traversal of the B-Tree:\n";
- tree.traverse();
- cout << endl;
- // 搜索键值
- int key = 6;
- cout << "Searching for key " << key << " in the B-Tree..." << endl;
- auto result = tree.search(key);
- if (result != nullptr) {
- cout << "Key " << key << " found in the B-Tree.\n";
- } else {
- cout << "Key " << key << " not found in the B-Tree.\n";
- }
- return 0;
- }
复制代码 CPP版本b树
- 数据结构设计:
- BTreeNode 类表现 B 树的节点,包罗键值数组 (keys) 和子节点指针数组 (children)。
- BTree 类表现 B 树,封装了树的根节点和相干操纵。
- 核心操纵:
- 创建节点:通过构造函数动态创建新节点。
- 插入:
- 假如根节点已满,会创建一个新根节点并分裂旧根。
- 插入操纵通过递归调整子节点,确保 B 树的平衡性。
- 查找:在节点中二分查找键值并递归到子节点。
- 遍历:中序遍历全部键值。
- 加强结实性:
- 使用 vector 自动管理数组内存,避免手动分配和释放。
- 使用 shared_ptr 管理节点的生命周期,防止内存泄漏。
- 异常检测和边界条件处理(如空树或满节点)。
- 输入输出:
- 插入一组数据构建 B 树。
- 遍历 B 树,输出全部键值。
- 搜索指定键值,输出是否存在。
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- // 定义 B+树的最小度数 T
- #define T 3
- // 定义 B+树节点结构
- typedef struct BPTreeNode {
- int *keys; // 键值数组
- struct BPTreeNode **children; // 子节点指针数组
- int n; // 当前节点的键值数量
- bool isLeaf; // 是否为叶子节点
- struct BPTreeNode *next; // 用于叶子节点的链表指针
- } BPTreeNode;
- // 创建一个新节点
- BPTreeNode *createNode(bool isLeaf) {
- BPTreeNode *node = (BPTreeNode *)malloc(sizeof(BPTreeNode));
- if (!node) {
- fprintf(stderr, "Memory allocation failed for BPTreeNode.\n");
- exit(EXIT_FAILURE);
- }
- node->keys = (int *)malloc((2 * T - 1) * sizeof(int));
- node->children = (BPTreeNode **)malloc(2 * T * sizeof(BPTreeNode *));
- node->n = 0;
- node->isLeaf = isLeaf;
- node->next = NULL;
- if (!node->keys || !node->children) {
- fprintf(stderr, "Memory allocation failed for keys or children.\n");
- exit(EXIT_FAILURE);
- }
- return node;
- }
- // 遍历 B+树的叶子节点(范围查询)
- void traverse(BPTreeNode *root) {
- if (!root) return;
- // 找到最左叶子节点
- while (!root->isLeaf) {
- root = root->children[0];
- }
- // 遍历所有叶子节点
- while (root) {
- for (int i = 0; i < root->n; i++) {
- printf("%d ", root->keys[i]);
- }
- root = root->next;
- }
- printf("\n");
- }
- // 搜索键值
- BPTreeNode *search(BPTreeNode *root, int key) {
- if (!root) return NULL;
- int i = 0;
- // 找到键值范围
- while (i < root->n && key > root->keys[i]) {
- i++;
- }
- if (root->isLeaf) {
- // 如果是叶子节点,检查是否找到
- if (i < root->n && root->keys[i] == key) {
- return root;
- }
- return NULL;
- }
- // 如果不是叶子节点,递归到子节点
- return search(root->children[i], key);
- }
- // 分裂非叶子节点的子节点
- void splitNonLeafChild(BPTreeNode *parent, int idx, BPTreeNode *child) {
- // 创建新节点
- BPTreeNode *newNode = createNode(child->isLeaf);
- newNode->n = T - 1;
- // 将后半部分的键值复制到新节点
- for (int i = 0; i < T - 1; i++) {
- newNode->keys[i] = child->keys[i + T];
- }
- // 如果不是叶子节点,将子节点指针复制到新节点
- if (!child->isLeaf) {
- for (int i = 0; i < T; i++) {
- newNode->children[i] = child->children[i + T];
- }
- }
- child->n = T - 1;
- // 插入新的子节点到父节点
- for (int i = parent->n; i >= idx + 1; i--) {
- parent->children[i + 1] = parent->children[i];
- }
- parent->children[idx + 1] = newNode;
- // 将中间键值插入到父节点
- for (int i = parent->n - 1; i >= idx; i--) {
- parent->keys[i + 1] = parent->keys[i];
- }
- parent->keys[idx] = child->keys[T - 1];
- parent->n++;
- }
- // 分裂叶子节点
- void splitLeafChild(BPTreeNode *parent, int idx, BPTreeNode *leaf) {
- // 创建一个新叶子节点
- BPTreeNode *newLeaf = createNode(true);
- newLeaf->n = T - 1;
- // 将后半部分的键值复制到新叶子节点
- for (int i = 0; i < T - 1; i++) {
- newLeaf->keys[i] = leaf->keys[i + T - 1];
- }
- leaf->n = T - 1;
- // 设置叶子节点的链表指针
- newLeaf->next = leaf->next;
- leaf->next = newLeaf;
- // 插入新叶子节点到父节点
- for (int i = parent->n; i >= idx + 1; i--) {
- parent->children[i + 1] = parent->children[i];
- }
- parent->children[idx + 1] = newLeaf;
- // 将新叶子节点的第一个键值插入到父节点
- for (int i = parent->n - 1; i >= idx; i--) {
- parent->keys[i + 1] = parent->keys[i];
- }
- parent->keys[idx] = newLeaf->keys[0];
- parent->n++;
- }
- // 插入到非满节点中
- void insertNonFull(BPTreeNode *node, int key) {
- int i = node->n - 1;
- if (node->isLeaf) {
- // 找到插入位置
- while (i >= 0 && key < node->keys[i]) {
- node->keys[i + 1] = node->keys[i];
- i--;
- }
- node->keys[i + 1] = key;
- node->n++;
- } else {
- // 找到子节点位置
- while (i >= 0 && key < node->keys[i]) {
- i--;
- }
- i++;
- // 如果子节点已满
- if (node->children[i]->n == 2 * T - 1) {
- if (node->children[i]->isLeaf) {
- splitLeafChild(node, i, node->children[i]);
- } else {
- splitNonLeafChild(node, i, node->children[i]);
- }
- // 确定插入位置
- if (key > node->keys[i]) {
- i++;
- }
- }
- insertNonFull(node->children[i], key);
- }
- }
- // 插入键值到 B+树
- void insert(BPTreeNode **rootRef, int key) {
- BPTreeNode *root = *rootRef;
- if (!root) {
- // 如果根节点为空,创建一个新节点
- root = createNode(true);
- root->keys[0] = key;
- root->n = 1;
- *rootRef = root;
- return;
- }
- // 如果根节点已满
- if (root->n == 2 * T - 1) {
- // 创建一个新根节点
- BPTreeNode *newRoot = createNode(false);
- newRoot->children[0] = root;
- // 分裂根节点
- if (root->isLeaf) {
- splitLeafChild(newRoot, 0, root);
- } else {
- splitNonLeafChild(newRoot, 0, root);
- }
- // 插入到新根节点的合适位置
- int i = (key > newRoot->keys[0]) ? 1 : 0;
- insertNonFull(newRoot->children[i], key);
- *rootRef = newRoot;
- } else {
- insertNonFull(root, key);
- }
- }
- // 释放 B+树节点
- void freeBPTree(BPTreeNode *node) {
- if (!node) return;
- if (!node->isLeaf) {
- for (int i = 0; i <= node->n; i++) {
- freeBPTree(node->children[i]);
- }
- }
- free(node->keys);
- free(node->children);
- free(node);
- }
- // 主函数
- int main() {
- BPTreeNode *root = NULL;
- // 插入数据
- insert(&root, 10);
- insert(&root, 20);
- insert(&root, 5);
- insert(&root, 6);
- insert(&root, 12);
- insert(&root, 30);
- insert(&root, 7);
- insert(&root, 17);
- // 遍历 B+树
- printf("Traversal of the B+ Tree:\n");
- traverse(root);
- // 搜索键值
- int key = 6;
- printf("Searching for key %d in the B+ Tree...\n", key);
- BPTreeNode *result = search(root, key);
- if (result) {
- printf("Key %d found in the B+ Tree.\n", key);
- } else {
- printf("Key %d not found in the B+ Tree.\n", key);
- }
- // 释放 B+树
- freeBPTree(root);
- return 0;
- }
复制代码 C语言版本b+树
- 数据结构:
- BPTreeNode 表现 B+树的节点,包罗 keys、children 和 next(叶子节点链表指针)。
- 支持叶子节点链表结构,优化范围查询。
- 主要功能:
- 插入:自动处理节点分裂,支持叶子和非叶子节点分裂。
- 搜索:递归搜索键值。
- 遍历:从叶子节点链表输出全部键值。
- 内存释放:递归释放全部节点,避免内存泄漏。
- 结实性:
- 检查内存分配是否乐成,失败时终止步伐。
- 处理空树和根节点分裂等边界情况。
- 测试功能:
- 插入一组数据,输出全部键值。
- 搜索特定键值,输出是否找到。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |