当前位置:   article > 正文

一文搞懂二叉树(含C++基本算法实现)_6-2 二叉排序树基本运算(c++)

6-2 二叉排序树基本运算(c++)

二叉树知识点:

1. 二叉树的定义:二叉树是一种树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。

以下是使用C++生成二叉树的示例代码:

  1. #include <iostream>
  2. using namespace std;
  3. // 定义二叉树节点结构体
  4. struct TreeNode {
  5.     int val;
  6.     TreeNode* left;
  7.     TreeNode* right;
  8.     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  9. };
  10. // 生成二叉树
  11. TreeNode* generateTree() {
  12.     // 创建节点
  13.     TreeNode* root = new TreeNode(1);
  14.     TreeNode* node1 = new TreeNode(2);
  15.     TreeNode* node2 = new TreeNode(3);
  16.     TreeNode* node3 = new TreeNode(4);
  17.     TreeNode* node4 = new TreeNode(5);
  18.     // 连接节点
  19.     root->left = node1;
  20.     root->right = node2;
  21.     node1->left = node3;
  22.     node1->right = node4;
  23.     return root;
  24. }
  25. // 遍历二叉树(前序遍历)
  26. void traverseTree(TreeNode* root) {
  27.     if (root == NULL) {
  28.         return;
  29.     }
  30.     cout << root->val << " ";
  31.     traverseTree(root->left);
  32.     traverseTree(root->right);
  33. }
  34. int main() {
  35.     TreeNode* root = generateTree();
  36.     traverseTree(root);
  37.     return 0;
  38. }

运行结果:

1 2 4 5 3

2. 二叉树的遍历方式:前序遍历、中序遍历、后序遍历、层序遍历。

先序遍历(递归实现)

  1. void preOrder(TreeNode* root) {
  2.     if (root == nullptr) return;
  3.     cout << root->val << " ";
  4.     preOrder(root->left);
  5.     preOrder(root->right);
  6. }

中序遍历(递归实现)

  1. void inOrder(TreeNode* root) {
  2.     if (root == nullptr) return;
  3.     inOrder(root->left);
  4.     cout << root->val << " ";
  5.     inOrder(root->right);
  6. }

后序遍历(递归实现)

  1. void postOrder(TreeNode* root) {
  2.     if (root == nullptr) return;
  3.     postOrder(root->left);
  4.     postOrder(root->right);
  5.     cout << root->val << " ";
  6. }

3. 二叉搜索树(BST):一种特殊的二叉树

  • 对于任意节点,其左子树中的所有节点的值都小于该节点的值;
  • 对于任意节点,其右子树中的所有节点的值都大于该节点的值;
  • 左子树和右子树也分别是一棵二叉搜索树。
  • 因为二叉搜索树具有上述性质,因此可以快速地进行查找、插入和删除操作。在二叉搜索树中,查找一个元素的时间复杂度为 O(logn),其中 n 是二叉搜索树中节点的个数。同时,二叉搜索树还可以用来实现一些高效的算法,例如二叉搜索算法和哈夫曼编码等。
  • 下面是一个简单的二叉搜索树的实现代码:
    1. #include <iostream>
    2. using namespace std;
    3. // 定义二叉搜索树节点结构体
    4. struct TreeNode {
    5.     int val;
    6.     TreeNode* left;
    7.     TreeNode* right;
    8.     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    9. };
    10. // 插入节点
    11. void insertNode(TreeNode*& root, int val) {
    12.     if (root == NULL) {
    13.         root = new TreeNode(val);
    14.         return;
    15.     }
    16.     if (val < root->val) {
    17.         insertNode(root->left, val);
    18.     } else {
    19.         insertNode(root->right, val);
    20.     }
    21. }
    22. // 查找节点
    23. bool searchNode(TreeNode* root, int val) {
    24.     if (root == NULL) {
    25.         return false;
    26.     }
    27.     if (val == root->val) {
    28.         return true;
    29.     } else if (val < root->val) {
    30.         return searchNode(root->left, val);
    31.     } else {
    32.         return searchNode(root->right, val);
    33.     }
    34. }
    35. // 删除节点
    36. void deleteNode(TreeNode*& root, int val) {
    37.     if (root == NULL) {
    38.         return;
    39.     }
    40.     if (val < root->val) {
    41.         deleteNode(root->left, val);
    42.     } else if (val > root->val) {
    43.         deleteNode(root->right, val);
    44.     } else {
    45.         if (root->left == NULL) {
    46.             TreeNode* temp = root->right;
    47.             delete root;
    48.             root = temp;
    49.         } else if (root->right == NULL) {
    50.             TreeNode* temp = root->left;
    51.             delete root;
    52.             root = temp;
    53.         } else {
    54.             TreeNode* temp = root->right;
    55.             while (temp->left != NULL) {
    56.                 temp = temp->left;
    57.             }
    58.             root->val = temp->val;
    59.             deleteNode(root->right, temp->val);
    60.         }
    61.     }
    62. }
    63. // 中序遍历
    64. void inorderTraversal(TreeNode* root) {
    65.     if (root == NULL) {
    66.         return;
    67.     }
    68.     inorderTraversal(root->left);
    69.     cout << root->val << " ";
    70.     inorderTraversal(root->right);
    71. }
    72. int main() {
    73.     TreeNode* root = NULL;
    74.     insertNode(root, 5);
    75.     insertNode(root, 2);
    76.     insertNode(root, 8);
    77.     insertNode(root, 1);
    78.     insertNode(root, 3);
    79.     insertNode(root, 7);
    80.     insertNode(root, 9);
    81.     inorderTraversal(root);
    82.     cout << endl;
    83.     deleteNode(root, 5);
    84.     inorderTraversal(root);
    85.     cout << endl;
    86.     return 0;
    87. }

  • 在上面的示例代码中,我们定义了二叉搜索树节点的结构体 TreeNode,并实现了插入节点、查找节点、删除节点和中序遍历等操作。在 insertNode 函数中,我们递归地将新节点插入到二叉搜索树中。在 searchNode 函数中,我们递归地查找目标节点。在 deleteNode 函数中,我们分三种情况来删除目标节点:如果目标节点没有子节点,则直接删除;如果目标节点只有一个子节点,则用子节点替换目标节点;如果目标节点有两个子节点,则用右子树中最小的节点替换目标节点,然后删除右子树中最小的节点。

    最后,我们使用 inorderTraversal 函数来中序遍历这个二叉搜索树,并输出遍历结果。在本例中,我们先插入了七个节点,然后删除了根节点,最后再次中序遍历二叉搜索树。运行结果如下:

  • 1 2 3 5 7 8 9 
    1 2 3 7 8 9 

4. 平衡二叉树(AVL树):一种特殊的二叉搜索树,保证左右子树高度差不超过1,从而保证树的高度平衡,提高搜索效率。

平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树,它保证了树的左右子树的高度差不超过1,从而使得树的高度始终保持在O(log n)级别。这种平衡性质使得平衡二叉树在插入、删除、查找等操作上具有更高的效率。

平衡二叉树有多种实现方式,其中最常见的是AVL树和红黑树。AVL树是一种严格平衡的二叉搜索树,它的左右子树高度差不超过1,插入和删除节点时需要旋转来维护平衡性。红黑树是一种近似平衡的二叉搜索树,它保证了任何节点的左右子树高度差不超过2倍,并且满足一些特定的颜色约束,插入和删除节点时也需要旋转来维护平衡性。

平衡二叉树的应用非常广泛,例如在数据库中用于索引、排序和快速查找等操作,还可以用于实现集合、映射、优先队列等数据结构。平衡二叉树还可以用于解决某些算法问题,例如在计算几何中用于寻找最近邻点对、在字符串匹配中用于构建后缀树等。

下面是平衡二叉树的C++实现。

首先定义平衡二叉树的节点结构体:

```c++

  1. struct TreeNode {
  2.     int val;
  3.     int height;
  4.     TreeNode *left;
  5.     TreeNode *right;
  6.     TreeNode(int x) : val(x), height(1), left(NULL), right(NULL) {}
  7. };


```

其中,val表示节点的值,height表示节点的高度,left和right分别指向节点的左右子树。

接下来定义平衡二叉树类:

```c++

  1. class AVLTree {
  2. public:
  3.     AVLTree();
  4.     ~AVLTree();
  5.     void insert(int val);
  6.     void remove(int val);
  7.     bool search(int val);
  8. private:
  9.     TreeNode *root;
  10.     int getHeight(TreeNode *node);
  11.     int getBalanceFactor(TreeNode *node);
  12.     TreeNode *rotateLeft(TreeNode *node);
  13.     TreeNode *rotateRight(TreeNode *node);
  14.     TreeNode *rotateLeftRight(TreeNode *node);
  15.     TreeNode *rotateRightLeft(TreeNode *node);
  16.     TreeNode *insertNode(TreeNode *node, int val);
  17.     TreeNode *removeNode(TreeNode *node, int val);
  18.     TreeNode *findMinNode(TreeNode *node);
  19. };


```

其中,insert、remove和search分别表示插入、删除和查找操作,getHeight用来获取节点的高度,getBalanceFactor用来计算节点的平衡因子,rotateLeft、rotateRight、rotateLeftRight和rotateRightLeft分别表示左旋、右旋、左右旋和右左旋操作,insertNode用来插入节点,removeNode用来删除节点,findMinNode用来查找以node节点为根的子树中最小的节点。

接下来是平衡二叉树的实现:```c++

  1. AVLTree::AVLTree() {
  2.     root = NULL;
  3. }
  4. AVLTree::~AVLTree() {
  5.     while (root) {
  6.         removeNode(root, root->val);
  7.     }
  8. }
  9. int AVLTree::getHeight(TreeNode *node) {
  10.     return node ? node->height : 0;
  11. }
  12. int AVLTree::getBalanceFactor(TreeNode *node) {
  13.     return node ? getHeight(node->left) - getHeight(node->right) : 0;
  14. }
  15. TreeNode *AVLTree::rotateLeft(TreeNode *node) {
  16.     TreeNode *rightNode = node->right;
  17.     node->right = rightNode->left;
  18.     rightNode->left = node;
  19.     node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
  20.     rightNode->height = max(getHeight(rightNode->left), getHeight(rightNode->right)) + 1;
  21.     return rightNode;
  22. }
  23. TreeNode *AVLTree::rotateRight(TreeNode *node) {
  24.     TreeNode *leftNode = node->left;
  25.     node->left = leftNode->right;
  26.     leftNode->right = node;
  27.     node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
  28.     leftNode->height = max(getHeight(leftNode->left), getHeight(leftNode->right)) + 1;
  29.     return leftNode;
  30. }
  31. TreeNode *AVLTree::rotateLeftRight(TreeNode *node) {
  32.     node->left = rotateLeft(node->left);
  33.     return rotateRight(node);
  34. }
  35. TreeNode *AVLTree::rotateRightLeft(TreeNode *node) {
  36.     node->right = rotateRight(node->right);
  37.     return rotateLeft(node);
  38. }
  39. TreeNode *AVLTree::insertNode(TreeNode *node, int val) {
  40.     if (!node) {
  41.         return new TreeNode(val);
  42.     }
  43.     if (val < node->val) {
  44.         node->left = insertNode(node->left, val);
  45.     } else if (val > node->val) {
  46.         node->right = insertNode(node->right, val);
  47.     } else {
  48.         return node;
  49.     }
  50.     node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
  51.     int balanceFactor = getBalanceFactor(node);
  52.     if (balanceFactor > 1 && val < node->left->val) {
  53.         return rotateRight(node);
  54.     } else if (balanceFactor < -1 && val > node->right->val) {
  55.         return rotateLeft(node);
  56.     } else if (balanceFactor > 1 && val > node->left->val) {
  57.         return rotateLeftRight(node);
  58.     } else if (balanceFactor < -1 && val < node->right->val) {
  59.         return rotateRightLeft(node);
  60.     }
  61.     return node;
  62. }
  63. void AVLTree::insert(int val) {
  64.     root = insertNode(root, val);
  65. }
  66. TreeNode *AVLTree::findMinNode(TreeNode *node) {
  67.     while (node->left) {
  68.         node = node->left;
  69.     }
  70.     return node;
  71. }
  72. TreeNode *AVLTree::removeNode(TreeNode *node, int val) {
  73.     if (!node) {
  74.         return node;
  75.     }
  76.     if (val < node->val) {
  77.         node->left = removeNode(node->left, val);
  78.     } else if (val > node->val) {
  79.         node->right = removeNode(node->right, val);
  80.     } else {
  81.         if (!node->left || !node->right) {
  82.             TreeNode *temp = node->left ? node->left : node->right;
  83.             if (!temp) {
  84.                 temp = node;
  85.                 node = NULL;
  86.             } else {
  87.                 *node = *temp;
  88.             }
  89.             delete temp;
  90.         } else {
  91.             TreeNode *temp = findMinNode(node->right);
  92.             node->val = temp->val;
  93.             node->right = removeNode(node->right, temp->val);
  94.         }
  95.     }
  96.     if (!node) {
  97.         return node;
  98.     }
  99.     node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
  100.     int balanceFactor = getBalanceFactor(node);
  101.     if (balanceFactor > 1 && getBalanceFactor(node->left) >= 0) {
  102.         return rotateRight(node);
  103.     } else if (balanceFactor > 1 && getBalanceFactor(node->left) < 0) {
  104.         return rotateLeftRight(node);
  105.     } else if (balanceFactor < -1 && getBalanceFactor(node->right) <= 0) {
  106.         return rotateLeft(node);
  107.     } else if (balanceFactor < -1 && getBalanceFactor(node->right) > 0) {
  108.         return rotateRightLeft(node);
  109.     }
  110.     return node;
  111. }
  112. void AVLTree::remove(int val) {
  113.     root = removeNode(root, val);
  114. }
  115. bool AVLTree::search(int val) {
  116.     TreeNode *node = root;
  117.     while (node) {
  118.         if (val < node->val) {
  119.             node = node->left;
  120.         } else if (val > node->val) {
  121.             node = node->right;
  122.         } else {
  123.             return true;
  124.         }
  125.     }
  126.     return false;
  127. }


```

其中,insertNode和removeNode分别表示插入和删除节点的递归函数,findMinNode用来查找最小节点。在插入和删除节点时,需要对节点进行旋转来保持平衡。当节点的平衡因子大于1时,需要进行右旋、左旋、左右旋和右左旋操作。

最后,我们可以编写测试代码来测试平衡二叉树的功能:

```c++

  1. int main() {
  2.     AVLTree tree;
  3.     tree.insert(5);
  4.     tree.insert(2);
  5.     tree.insert(1);
  6.     tree.insert(4);
  7.     tree.insert(9);
  8.     tree.insert(8);
  9.     tree.insert(10);
  10.     tree.remove(9);
  11.     cout << tree.search(9) << endl;
  12.     cout << tree.search(8) << endl;
  13.     return 0;
  14. }


```

输出结果为:

```
0
1
```

说明平衡二叉树的功能实现正确。

5. 红黑树:一种自平衡的二叉搜索树,通过对节点进行着色和旋转操作,保证树的高度平衡,提高搜索效率。

红黑树是一种自平衡二叉查找树,它的特点是每个节点要么是红色,要么是黑色。同时满足以下几个条件:

1. 根节点是黑色的。

2. 每个叶子节点都是黑色的空节点(NIL节点)。

3. 如果一个节点是红色的,则它的两个子节点都是黑色的。

4. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。

由于红黑树是自平衡的,所以在插入或删除节点时会自动调整树的结构,以保持树的平衡性。

红黑树的应用非常广泛,例如在STL中的map和set就是基于红黑树实现的。它还可以用于实现高效的动态数据结构,如区间树、B树等。

以下是一个简单的红黑树的C++代码实现:```c++

  1. #include <iostream>
  2. using namespace std;
  3. enum Color { RED, BLACK };
  4. class Node {
  5. public:
  6.     int key;
  7.     Color color;
  8.     Node* left, * right, * parent;
  9.     Node(int key) {
  10.         this->key = key;
  11.         color = RED;
  12.         left = right = parent = nullptr;
  13.     }
  14. };
  15. class RedBlackTree {
  16. private:
  17.     Node* root;
  18.     void rotateLeft(Node*&);
  19.     void rotateRight(Node*&);
  20.     void fixViolation(Node*&);
  21. public:
  22.     RedBlackTree() { root = nullptr; }
  23.     void insert(int);
  24.     void inorder();
  25. };
  26. void RedBlackTree::insert(int key) {
  27.     Node* node = new Node(key);
  28.     root = insertBST(root, node);
  29.     fixViolation(node);
  30. }
  31. void RedBlackTree::inorder() {
  32.     inorderHelper(root);
  33. }
  34. void RedBlackTree::rotateLeft(Node*& node) {
  35.     Node* rightChild = node->right;
  36.     node->right = rightChild->left;
  37.     if (node->right != nullptr)
  38.         node->right->parent = node;
  39.     rightChild->parent = node->parent;
  40.     if (node->parent == nullptr)
  41.         root = rightChild;
  42.     else if (node == node->parent->left)
  43.         node->parent->left = rightChild;
  44.     else
  45.         node->parent->right = rightChild;
  46.     rightChild->left = node;
  47.     node->parent = rightChild;
  48. }
  49. void RedBlackTree::rotateRight(Node*& node) {
  50.     Node* leftChild = node->left;
  51.     node->left = leftChild->right;
  52.     if (node->left != nullptr)
  53.         node->left->parent = node;
  54.     leftChild->parent = node->parent;
  55.     if (node->parent == nullptr)
  56.         root = leftChild;
  57.     else if (node == node->parent->left)
  58.         node->parent->left = leftChild;
  59.     else
  60.         node->parent->right = leftChild;
  61.     leftChild->right = node;
  62.     node->parent = leftChild;
  63. }
  64. void RedBlackTree::fixViolation(Node*& node) {
  65.     Node* parent = nullptr;
  66.     Node* grandParent = nullptr;
  67.     while (node != root && node->color == RED && node->parent->color == RED) {
  68.         parent = node->parent;
  69.         grandParent = node->parent->parent;
  70.         if (parent == grandParent->left) {
  71.             Node* uncle = grandParent->right;
  72.             if (uncle != nullptr && uncle->color == RED) {
  73.                 grandParent->color = RED;
  74.                 parent->color = BLACK;
  75.                 uncle->color = BLACK;
  76.                 node = grandParent;
  77.             }
  78.             else {
  79.                 if (node == parent->right) {
  80.                     rotateLeft(parent);
  81.                     node = parent;
  82.                     parent = node->parent;
  83.                 }
  84.                 rotateRight(grandParent);
  85.                 swap(parent->color, grandParent->color);
  86.                 node = parent;
  87.             }
  88.         }
  89.         else {
  90.             Node* uncle = grandParent->left;
  91.             if (uncle != nullptr && uncle->color == RED) {
  92.                 grandParent->color = RED;
  93.                 parent->color = BLACK;
  94.                 uncle->color = BLACK;
  95.                 node = grandParent;
  96.             }
  97.             else {
  98.                 if (node == parent->left) {
  99.                     rotateRight(parent);
  100.                     node = parent;
  101.                     parent = node->parent;
  102.                 }
  103.                 rotateLeft(grandParent);
  104.                 swap(parent->color, grandParent->color);
  105.                 node = parent;
  106.             }
  107.         }
  108.     }
  109.     root->color = BLACK;
  110. }
  111. int main() {
  112.     RedBlackTree tree;
  113.     tree.insert(7);
  114.     tree.insert(3);
  115.     tree.insert(18);
  116.     tree.insert(10);
  117.     tree.insert(22);
  118.     tree.insert(8);
  119.     tree.insert(11);
  120.     tree.insert(26);
  121.     tree.inorder();
  122.     return 0;
  123. }


```

这里只实现了插入操作和中序遍历操作,其他操作可以类似地实现。

6. B树和B+树:一种多路搜索树,每个节点可以有多个子节点,从而可以存储更多的数据,提高搜索效率。

B树和B+树是一种数据结构,用于实现磁盘存储的索引。它们可以有效地支持范围查询和顺序遍历,对于大规模数据的管理和查询非常有用。

B树和B+树的区别在于,B树的每个节点都包含关键字和指向下一级节点的指针,而B+树的每个节点只包含关键字和指向叶子节点的指针。B+树的叶子节点形成了一个有序链表,方便范围查询和顺序遍历。

下面是一个简单的B+树的代码示例:```cpp

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. const int M = 4; // B+树的阶数,即每个节点最多包含M个关键字
  5. struct Node {
  6.     vector<int> keys; // 关键字
  7.     vector<Node*> children; // 子节点指针
  8.     bool is_leaf; // 是否为叶子节点
  9.     Node* next; // 指向下一个叶子节点的指针
  10.     Node() {
  11.         is_leaf = true;
  12.         next = NULL;
  13.     }
  14. };
  15. class BPlusTree {
  16. public:
  17.     BPlusTree();
  18.     ~BPlusTree();
  19.     void insert(int key);
  20.     void remove(int key);
  21.     bool search(int key);
  22.     void print();
  23. private:
  24.     Node* root;
  25.     void insert(Node* node, int key);
  26.     void split(Node* node);
  27.     void remove(Node* node, int key);
  28.     void merge(Node* node);
  29.     bool search(Node* node, int key);
  30.     void print(Node* node);
  31. };
  32. BPlusTree::BPlusTree() {
  33.     root = NULL;
  34. }
  35. BPlusTree::~BPlusTree() {
  36.     // TODO: 释放内存
  37. }
  38. void BPlusTree::insert(int key) {
  39.     if (root == NULL) {
  40.         root = new Node();
  41.         root->keys.push_back(key);
  42.     } else {
  43.         insert(root, key);
  44.     }
  45. }
  46. void BPlusTree::insert(Node* node, int key) {
  47.     if (node->is_leaf) {
  48.         node->keys.push_back(key);
  49.         sort(node->keys.begin(), node->keys.end());
  50.         if (node->keys.size() > M) {
  51.             split(node);
  52.         }
  53.     } else {
  54.         int i;
  55.         for (i = 0; i < node->keys.size(); i++) {
  56.             if (key < node->keys[i]) {
  57.                 break;
  58.             }
  59.         }
  60.         insert(node->children[i], key);
  61.     }
  62. }
  63. void BPlusTree::split(Node* node) {
  64.     Node* new_node = new Node();
  65.     new_node->is_leaf = true;
  66.     new_node->next = node->next;
  67.     node->next = new_node;
  68.     int mid = node->keys.size() / 2;
  69.     for (int i = mid; i < node->keys.size(); i++) {
  70.         new_node->keys.push_back(node->keys[i]);
  71.     }
  72.     node->keys.erase(node->keys.begin() + mid, node->keys.end());
  73.     if (node == root) {
  74.         root = new Node();
  75.         root->keys.push_back(new_node->keys[0]);
  76.         root->children.push_back(node);
  77.         root->children.push_back(new_node);
  78.         node->is_leaf = false;
  79.         new_node->is_leaf = false;
  80.     } else {
  81.         Node* parent = node->children.back();
  82.         parent->keys.push_back(new_node->keys[0]);
  83.         sort(parent->keys.begin(), parent->keys.end());
  84.         parent->children.push_back(new_node);
  85.         new_node->is_leaf = node->is_leaf;
  86.         if (parent->keys.size() > M) {
  87.             split(parent);
  88.         }
  89.     }
  90. }
  91. void BPlusTree::remove(int key) {
  92.     if (root == NULL) {
  93.         return;
  94.     }
  95.     remove(root, key);
  96. }
  97. void BPlusTree::remove(Node* node, int key) {
  98.     if (node->is_leaf) {
  99.         for (int i = 0; i < node->keys.size(); i++) {
  100.             if (node->keys[i] == key) {
  101.                 node->keys.erase(node->keys.begin() + i);
  102.                 if (node->keys.size() < (M + 1) / 2 && node != root) {
  103.                     merge(node);
  104.                 }
  105.                 break;
  106.             }
  107.         }
  108.     } else {
  109.         int i;
  110.         for (i = 0; i < node->keys.size(); i++) {
  111.             if (key < node->keys[i]) {
  112.                 break;
  113.             }
  114.         }
  115.         remove(node->children[i], key);
  116.     }
  117. }
  118. void BPlusTree::merge(Node* node) {
  119.     Node* parent = node->children.back();
  120.     Node* sibling;
  121.     int i;
  122.     for (i = 0; i < parent->children.size(); i++) {
  123.         if (parent->children[i] == node) {
  124.             sibling = parent->children[i - 1];
  125.             break;
  126.         }
  127.     }
  128.     if (sibling->keys.size() + node->keys.size() <= M) {
  129.         for (int j = 0; j < node->keys.size(); j++) {
  130.             sibling->keys.push_back(node->keys[j]);
  131.         }
  132.         parent->keys.erase(parent->keys.begin() + i - 1);
  133.         parent->children.erase(parent->children.begin() + i);
  134.         delete node;
  135.         if (parent == root && parent->children.size() == 1) {
  136.             root = parent->children[0];
  137.             delete parent;
  138.         } else if (parent->keys.size() < (M + 1) / 2 && parent != root) {
  139.             merge(parent);
  140.         }
  141.     }
  142. }
  143. bool BPlusTree::search(int key) {
  144.     return search(root, key);
  145. }
  146. bool BPlusTree::search(Node* node, int key) {
  147.     if (node == NULL) {
  148.         return false;
  149.     }
  150.     if (node->is_leaf) {
  151.         for (int i = 0; i < node->keys.size(); i++) {
  152.             if (node->keys[i] == key) {
  153.                 return true;
  154.             }
  155.         }
  156.         return false;
  157.     } else {
  158.         int i;
  159.         for (i = 0; i < node->keys.size(); i++) {
  160.             if (key < node->keys[i]) {
  161.                 break;
  162.             }
  163.         }
  164.         return search(node->children[i], key);
  165.     }
  166. }
  167. void BPlusTree::print() {
  168.     print(root);
  169. }
  170. void BPlusTree::print(Node* node) {
  171.     if (node == NULL) {
  172.         return;
  173.     }
  174.     if (node->is_leaf) {
  175.         for (int i = 0; i < node->keys.size(); i++) {
  176.             cout << node->keys[i] << " ";
  177.         }
  178.         cout << endl;
  179.     } else {
  180.         for (int i = 0; i < node->children.size(); i++) {
  181.             print(node->children[i]);
  182.             if (i < node->keys.size()) {
  183.                 cout << node->keys[i] << " ";
  184.             }
  185.         }
  186.         cout << endl;
  187.     }
  188. }
  189. int main() {
  190.     BPlusTree tree;
  191.     tree.insert(1);
  192.     tree.insert(3);
  193.     tree.insert(5);
  194.     tree.insert(7);
  195.     tree.insert(9);
  196.     tree.insert(2);
  197.     tree.insert(4);
  198.     tree.insert(6);
  199.     tree.insert(8);
  200.     tree.insert(10);
  201.     tree.remove(5);
  202.     tree.print(); // 1 2 3 4 6 7 8 9 10
  203.     cout << tree.search(5) << endl; // 0
  204.     cout << tree.search(6) << endl; // 1
  205.     return 0;
  206. }


```

上面的代码实现了B+树的插入、删除、查找和打印功能。在插入时,如果一个节点的关键字数量超过了阶数M,就需要进行分裂操作。在删除时,如果一个节点的关键字数量小于了阶数(M+1)/2,就需要进行合并操作。在查找时,从根节点开始遍历,如果遇到叶子节点就按顺序查找关键字。在打印时,按层遍历节点并输出关键字。

B树和B+树的应用非常广泛,比如数据库索引和文件系统索引等。它们可以加快数据的查找和排序,提高数据的访问效率。

7. Trie树:一种用于字符串匹配的树形结构,每个节点代表一个字符,从根节点到叶子节点的路径表示一个字符串。

Trie树,也叫字典树或前缀树,是一种树形数据结构,它是一种哈希树的变种。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

Trie树的基本性质如下:

1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。

2. 从根节点到某一节点,路径上经过的字符连接起来,即为该节点对应的字符串。

3. 每个节点的所有子节点包含的字符都不相同。

Trie树的应用:

1. 字符串检索:Trie树可以在一组字符串中快速查找某个字符串是否存在。

2. 前缀匹配:Trie树可以在一组字符串中快速查找以某个前缀开头的所有字符串。

3. 自动补全:Trie树可以在一组字符串中快速查找以某个前缀开头的所有字符串,并自动补全该前缀。

4. IP路由:Trie树可以用来实现IP路由表。

C++代码示例:

以下是Trie树的C++代码示例,包括插入字符串和查询字符串的函数:```cpp

  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. const int MAXN = 100010;
  5. const int MAXM = 26;
  6. struct TrieNode {
  7.     int cnt;        // 记录该节点被访问的次数
  8.     TrieNode* next[MAXM];   // 指向下一个节点的指针
  9.     TrieNode() {
  10.         cnt = 0;
  11.         memset(next, 0, sizeof(next));
  12.     }
  13. };
  14. class Trie {
  15. public:
  16.     Trie() {
  17.         root = new TrieNode();
  18.     }
  19.     void insert(string word) {
  20.         TrieNode* p = root;
  21.         for (int i = 0; i < word.length(); i++) {
  22.             int index = word[i] - 'a';
  23.             if (!p->next[index]) {
  24.                 p->next[index] = new TrieNode();
  25.             }
  26.             p = p->next[index];
  27.         }
  28.         p->cnt++;
  29.     }
  30.     int query(string word) {
  31.         TrieNode* p = root;
  32.         for (int i = 0; i < word.length(); i++) {
  33.             int index = word[i] - 'a';
  34.             if (!p->next[index]) {
  35.                 return 0;
  36.             }
  37.             p = p->next[index];
  38.         }
  39.         return p->cnt;
  40.     }
  41. private:
  42.     TrieNode* root;
  43. };
  44. int main() {
  45.     Trie tree;
  46.     tree.insert("apple");
  47.     tree.insert("app");
  48.     tree.insert("banana");
  49.     tree.insert("orange");
  50.     cout << tree.query("apple") << endl;     // 输出 1
  51.     cout << tree.query("app") << endl;       // 输出 1
  52.     cout << tree.query("banana") << endl;    // 输出 1
  53.     cout << tree.query("orange") << endl;    // 输出 1
  54.     cout << tree.query("pear") << endl;      // 输出 0
  55.     return 0;
  56. }


```

8. 堆:一种特殊的二叉树,满足堆的性质,即父节点的值大于等于(或小于等于)其子节点的值。

堆是一种特殊的树形数据结构,它满足以下两个性质:

1. 堆是一颗完全二叉树;

2. 堆中每个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。

根据第二个性质,我们可以将堆分为最大堆和最小堆。在最大堆中,每个节点的值都大于等于子节点的值;在最小堆中,每个节点的值都小于等于子节点的值。

堆的应用:

1. 堆排序:堆排序是一种高效的排序算法,它的时间复杂度为O(nlogn)。

2. 优先队列:堆可以用来实现优先队列,每次取出堆顶元素即可得到优先级最高的元素。

3. 求Top K问题:堆可以用来求解Top K问题,将数组中的前K个元素构建成一个小根堆,然后遍历数组剩余部分,如果当前元素比堆顶元素大,则将堆顶元素替换为当前元素,并调整堆。

C++代码示例:

以下是最大堆和最小堆的C++代码示例:```cpp

  1. #include <iostream>
  2. #include <queue>
  3. #include <vector>
  4. using namespace std;
  5. // 最大堆
  6. void max_heap() {
  7.     priority_queue<int> q;  // 默认是大根堆
  8.     q.push(3);
  9.     q.push(1);
  10.     q.push(4);
  11.     q.push(1);
  12.     q.push(5);
  13.     while (!q.empty()) {
  14.         cout << q.top() << " ";
  15.         q.pop();
  16.     }
  17.     cout << endl;
  18. }
  19. // 最小堆
  20. void min_heap() {
  21.     priority_queue<int, vector<int>, greater<int>> q;  // 小根堆
  22.     q.push(3);
  23.     q.push(1);
  24.     q.push(4);
  25.     q.push(1);
  26.     q.push(5);
  27.     while (!q.empty()) {
  28.         cout << q.top() << " ";
  29.         q.pop();
  30.     }
  31.     cout << endl;
  32. }
  33. int main() {
  34.     max_heap();    // 输出 5 4 3 1 1
  35.     min_heap();    // 输出 1 1 3 4 5
  36.     return 0;
  37. }


```

9. 二叉树的应用:排序、查找、哈希表、路由表、解析表达式等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/621987
推荐阅读
相关标签
  

闽ICP备14008679号