B+树C++的实现

        之前写过b+树的基础概念和图解,数据库中B+树与索引,这里我继续用用c++代码实现一个简单的b+树,通过代码深入了解b+树,包含插入、查找和分裂的过程,我也写了详细的代码注释,以及过程的思路介绍。

这里创建一个节点的结构体,是b+树叶子节点和非叶子节点的内部结构

using namespace std;

const int M = 4; // B+树的阶数,M-1是B+树中每个节点最多存储的关键字个数

struct Node {
    int n; // 当前节点中关键字的个数
    vector<int> keys; // 关键字
    vector<Node*> children; // 子节点

    Node() {
        n = 0; //初始化关键词个数,空节点
        keys.resize(M-1); // 初始化keys数组大小为M-1,及4阶的b+树中,节点内最多3个关键词
        children.resize(M); // 初始化children数组大小为M,及4阶的b+树中,最多有4个子树
    }
};

初始化的节点就如图所示,关键词为2个,子节点为3个,都为空

这颗b+树中,根节点内的关键词个数就是1个,而他的子节点就是2个

下面定义了一个b+树的类,里面有insert插入和search查询的成员函数

class BPlusTree {
public:
    BPlusTree() {
        root = nullptr;  //根节点
    }
    ~BPlusTree() {  //析构函数
    }
    Node* root;
    
    // 插入关键字
    void insert(int key) {
        if (root == nullptr) { // 如果根节点为空,创建新节点作为根节点
            root = new Node();
            root->n = 1;
            root->keys[0] = key;
        } else {
            Node* node = findLeafNode(key); // 查找包含关键字的叶子节点,为后续插入找到节点
            insertInNode(node, key); // 在叶子节点中插入关键字
        }
    }

    // 查找关键字
    bool search(int key) {
        Node* node = findLeafNode(key); // 查找包含关键字的叶子节点
        for (int i = 0; i < node->n; i++) { // 遍历叶子节点中的关键字
            if (node->keys[i] == key) { // 如果找到目标关键字,返回true
                return true;
            }
        }
        return false; // 否则返回false
    }

插入的时候,如果根节点为空,创建新的根节点,不为空则需要先找到插入位置,再继续进行插入:

这是查找到所需要插入的节点

1.从根节点开始查找

2.对所插入的值和当前节点的关键词的值进行比较,并用 i 记录,比较后继续跳到当前节点的第i个子节点

3当当前节点是叶子节点,也就是不能继续向下查找时,返回当前节点

    // 查找包含关键字的叶子节点
    Node* findLeafNode(int key) {
        Node* node = root;
        while (node->children[0] != nullptr) { // 如果当前节点不是叶子节点,继续向下查找
            int i = 0;
            while (i < node->n && key >= node->keys[i]) { // 找到目标关键字应该插入的子节点
                i++;
            }
            node = node->children[i];
        }
        return node; // 返回叶子节点
    }

而查找关键词则需要在查询到节点后,遍历节点内的元素进行关键词的比较

查询4:

找到根节点的右子树节点,然后进行遍历,比较,查到到4

下面是向节点内插入关键字:

1 从最右侧开始比较,如果插入值小于当前关键词的值,则将当前关键词右移一位,并继续比较,直到对比完第一个关键词或对比到不小于的关键词,将插入值保存

2 如果关键词个数大于等于阶数,开始分裂节点

    // 在节点中插入关键字
    void insertInNode(Node* node, int key) {
        int i = node->n - 1; // 从当前节点中最右侧关键字开始遍历
        while (i >= 0 && key < node->keys[i]) { // 如果待插入的关键字比当前关键字小,则将当前关键字向右移动一位
            node->keys[i + 1] = node->keys[i];
            i--;
        }
        node->keys[i + 1] = key; // 将待插入的关键字插入到空出来的位置
        node->n++;

        if (node->n >= M) { // 如果当前节点中关键字个数超过了M-1,则需要分裂节点
            splitNode(node);
        }
    }

往下面这个节点插入  值   0

遍历节点内关键词,跟3进行对比,小于3,继续跟2对比,比2小,继续跟1对比,比1小,结束遍历,插入在1的左边

叶子节点的关键词个数大于等于阶数4,开始分裂

下面是分裂节点所需要的查找父节点、查找节点在父节点中的位置的两个函数

因为分裂节点的时候,是需要把一个关键词放入父节点中

 // 递归查找节点的父节点
    Node* getParent(Node* node, Node* child) {
        for (int i = 0; i <= node->n; i++) {
            if (node->children[i] == child) { // 如果当前节点是子节点的父节点,返回当前节点
                return node;
            }else if (node->children[i] != nullptr && child->keys[0] < node->keys[i]){ // 否则,继续向下查找
                return getParent(node->children[i], child);
            }
        }
        return nullptr;
    }

    // 查找节点在父节点中的位置
    int getChildIndex(Node* parent, Node* child) {
        for (int i = 0; i <= parent->n; i++) {
            if (parent->children[i] == child) { // 如果当前节点是子节点的父节点,返回当前节点的位置
                return i;
            }
        }
        return -1;
    }

插入时候分裂节点过程详述:

1  找到节点中中间位置以及关键字,这个中间位置的关键字后面是需要插入到父节点中,如分裂的节点是根节点则需要创新一个新的根节点存放这个中间位置的关键字

2 创建左字节点,存放小于中间关键字的关键字,并接到父节点

3  创建右字节点,存放大于等于中间关键字的关键字,并接到父节点

4  如果插入值的父节点的关键字的个数,大于阶数,需要继续分裂

插入时候分裂节点遇到的两种情况详解:

第一种情况,分裂的节点是根节点:

1 找到中间值 2 ,由于是根节点分裂,则需要创建新的根节点存储2

2  创建左字节点,存放小于中间值2的值,并接入父节点

3  创建右字节点,存放大于等于中间值2的值,并接入父节点

第二种情况,分裂的节点不是根节点:

插入值4

值插入叶子节点中,发现叶子节点需要分裂

1 将中间值4插入父节点中,查询到此节点的父节点,并插入,如果父节点也需要分裂,则先递归分裂父节点

2 创建左子节点接入父节点

3  创建右字节点接入父节点

    void splitNode(Node* node) {
        int mid = node->n / 2; // 找到中间位置
        int key = node->keys[mid]; // 中间关键字

        Node* left = new Node(); // 创建左子节点
        left->n = mid;
        for (int i = 0; i < mid; i++) { // 将左半部分关键字和子节点复制到新的节点中
            left->keys[i] = node->keys[i];
            left->children[i] = node->children[i];
        }
        left->children[mid] = node->children[mid];

        Node* right = new Node(); // 创建右子节点
        right->n = node->n - mid - 1;
        for (int i = mid + 1; i < node->n; i++) { // 将右半部分关键字和子节点复制到新的节点中
            right->keys[i - mid - 1] = node->keys[i];
            right->children[i - mid - 1] = node->children[i];
        }
        right->children[node->n - mid - 1] = node->children[node->n];

        if (node == root) { // 如果当前节点是根节点,需要创建新的根节点
            root = new Node();
            root->n = 1;
            root->keys[0] = key;
            root->children[0] = left;
            root->children[1] = right;
        } else { // 否则,将中间关键字插入到父节点中,并将左右子节点插入到父节点中
            Node* parent = getParent(root, node);
            insertInNode(parent,key); // 插入中间关键字到父节点中
            int index = getChildIndex(parent, node); // 获取当前节点在父节点中的位置
            parent->children[index] = left; // 将左子节点插入到父节点中
            parent->children[index + 1] = right; // 将右子节点插入到父节点中
            delete node; // 删除当前节点
        }
    }

下面是代码汇总:

#include <iostream>
#include <vector>

using namespace std;

const int M = 4; // B+树的阶数,M-1是B+树中每个节点最多存储的关键字个数

struct Node {
    int n; // 当前节点中关键字的个数
    vector<int> keys; // 关键字
    vector<Node*> children; // 子节点

    Node() {
        n = 0; //初始化关键词个数,空节点
        keys.resize(M-1); // 初始化keys数组大小为M-1
        children.resize(M); // 初始化children数组大小为M
    }
};

class BPlusTree {
public:
    BPlusTree() {
        root = nullptr;  //根节点
    }
    ~BPlusTree() {  //析构函数
    }
    Node* root;

    // 插入关键字
    void insert(int key) {
        if (root == nullptr) { // 如果根节点为空,创建新节点作为根节点
            root = new Node();
            root->n = 1;
            root->keys[0] = key;
        } else {
            Node* node = findLeafNode(key); // 查找包含关键字的叶子节点
            insertInNode(node, key); // 在叶子节点中插入关键字
        }
    }

    // 查找关键字
    bool search(int key) {
        Node* node = findLeafNode(key); // 查找包含关键字的叶子节点
        for (int i = 0; i < node->n; i++) { // 遍历叶子节点中的关键字
            if (node->keys[i] == key) { // 如果找到目标关键字,返回true
                return true;
            }
        }
        return false; // 否则返回false
    }

private:

    // 在节点中插入关键字
    void insertInNode(Node* node, int key) {
        int i = node->n - 1; // 从当前节点中最右侧关键字开始遍历
        while (i >= 0 && key < node->keys[i]) { // 如果待插入的关键字比当前关键字小,则将当前关键字向右移动一位
            node->keys[i + 1] = node->keys[i];
            i--;
        }
        node->keys[i + 1] = key; // 将待插入的关键字插入到空出来的位置
        node->n++;

        if (node->n >= M) { // 如果当前节点中关键字个数超过了M-1,则需要分裂节点
            splitNode(node);
        }
    }

    // 分裂节点
    void splitNode(Node* node) {
        int mid = node->n / 2; // 找到中间位置
        int key = node->keys[mid]; // 中间关键字

        Node* left = new Node(); // 创建左子节点
        left->n = mid;
        for (int i = 0; i < mid; i++) { // 将左半部分关键字和子节点复制到新的节点中
            left->keys[i] = node->keys[i];
            left->children[i] = node->children[i];
        }
        left->children[mid] = node->children[mid];

        Node* right = new Node(); // 创建右子节点
        right->n = node->n - mid - 1;
        for (int i = mid + 1; i < node->n; i++) { // 将右半部分关键字和子节点复制到新的节点中
            right->keys[i - mid - 1] = node->keys[i];
            right->children[i - mid - 1] = node->children[i];
        }
        right->children[node->n - mid - 1] = node->children[node->n];

        if (node == root) { // 如果当前节点是根节点,需要创建新的根节点
            root = new Node();
            root->n = 1;
            root->keys[0] = key;
            root->children[0] = left;
            root->children[1] = right;
        } else { // 否则,将中间关键字插入到父节点中,并将左右子节点插入到父节点中
            Node* parent = getParent(root, node);
            insertInNode(parent,key); // 插入中间关键字到父节点中
            int index = getChildIndex(parent, node); // 获取当前节点在父节点中的位置
            parent->children[index] = left; // 将左子节点插入到父节点中
            parent->children[index + 1] = right; // 将右子节点插入到父节点中
            delete node; // 删除当前节点
        }
    }

    // 查找包含关键字的叶子节点
    Node* findLeafNode(int key) {
        Node* node = root;
        while (node->children[0] != nullptr) { // 如果当前节点不是叶子节点,继续向下查找
            int i = 0;
            while (i < node->n && key >= node->keys[i]) { // 找到目标关键字应该插入的子节点
                i++;
            }
            node = node->children[i];
        }
        return node; // 返回叶子节点
    }

    // 查找节点的父节点
    Node* getParent(Node* node, Node* child) {
        for (int i = 0; i <= node->n; i++) {
            if (node->children[i] == child) { // 如果当前节点是子节点的父节点,返回当前节点
                return node;
            }else if (node->children[i] != nullptr && child->keys[0] < node->keys[i]){ // 否则,继续向下查找
                return getParent(node->children[i], child);
            }
        }
        return nullptr;
    }

    // 查找节点在父节点中的位置
    int getChildIndex(Node* parent, Node* child) {
        for (int i = 0; i <= parent->n; i++) {
            if (parent->children[i] == child) { // 如果当前节点是子节点的父节点,返回当前节点的位置
                return i;
            }
        }
        return -1;
    }
};

### LLaMA-Factory Project Setup with PyTorch and CUDA Configuration Tutorial For setting up the LLaMA-Factory project, ensuring that both Python environment creation and GPU support through CUDA are correctly configured is crucial. The following sections provide a detailed guide on how to set this up. #### Creating the Conda Environment To start off, it's important to establish an appropriate development environment using `conda`. This ensures all dependencies required by LLaMA-Factory can be managed effectively: ```bash conda create --name llama_factory python=3.11 ``` After creating the environment, activate it before proceeding further[^1]: ```bash conda activate llama_factory ``` #### Installing Required Packages Including PyTorch with CUDA Support Once inside the newly created virtual environment, install necessary packages including PyTorch specifically built for CUDA compatibility. It’s essential to choose versions of these libraries which work well together as indicated below: ```bash pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117 ``` This command installs PyTorch along with its extensions (`torchvision`, `torchaudio`) compiled against CUDA 11.7, assuming one has compatible hardware drivers installed already. #### Verifying Installation Success Post-installation verification steps help confirm whether everything was successfully put into place without issues related to missing components or misconfigurations: Check if CUDA-capable devices exist within your system via running small snippets like so in Python console after importing relevant modules from PyTorch library: ```python import torch print(torch.cuda.is_available()) print(torch.cuda.device_count()) print(torch.__version__) ``` If everything went smoothly during installation phase then output should indicate availability status being true alongside non-zero count value indicating presence of at least single GPU device available while also showing version string ending with '+cuXX' where XX represents specific major/minor release numbers associated with underlying NVIDIA driver stack used when building binary distributions provided above[^3]. #### Troubleshooting Common Issues Encountered During Deployment Phase In cases where users encounter errors such as "CUDA detection failed", several potential causes could lead to such failures ranging from mismatched software stacks down to improper driver installations. Ensuring correct setup involves checking multiple aspects starting from verifying proper functioning state of graphics card itself followed by confirming successful loading of corresponding kernel module responsible for interfacing between operating systems calls made towards accessing low-level functionalities exposed by said hardware component[^2]. --related questions-- 1. How do I resolve 'CUDA SETUP: CUDA detection failed!' error encountered while fine-tuning models? 2. What steps must be taken post-setup to ensure optimal performance tuning for deep learning tasks utilizing GPUs? 3. Can you explain more about choosing suitable versions among different releases offered under PyTorch distribution channels based upon existing infrastructure constraints? 4. Are there any additional tools recommended beyond those mentioned here for monitoring resource utilization metrics during model training sessions?
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值