以下是使用C++生成二叉树的示例代码:
#include
using namespace std;
// 定义二叉树节点结构体
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// 生成二叉树
TreeNode* generateTree() {
// 创建节点
TreeNode* root = new TreeNode(1);
TreeNode* node1 = new TreeNode(2);
TreeNode* node2 = new TreeNode(3);
TreeNode* node3 = new TreeNode(4);
TreeNode* node4 = new TreeNode(5);
// 连接节点
root->left = node1;
root->right = node2;
node1->left = node3;
node1->right = node4;
return root;
}
// 遍历二叉树(前序遍历)
void traverseTree(TreeNode* root) {
if (root == NULL) {
return;
}
cout << root->val << " ";
traverseTree(root->left);
traverseTree(root->right);
}
int main() {
TreeNode* root = generateTree();
traverseTree(root);
return 0;
}
运行结果:
1 2 4 5 3
void preOrder(TreeNode* root) {
if (root == nullptr) return;
cout << root->val << " ";
preOrder(root->left);
preOrder(root->right);
}
void inOrder(TreeNode* root) {
if (root == nullptr) return;
inOrder(root->left);
cout << root->val << " ";
inOrder(root->right);
}
void postOrder(TreeNode* root) {
if (root == nullptr) return;
postOrder(root->left);
postOrder(root->right);
cout << root->val << " ";
}
#include
using namespace std;
// 定义二叉搜索树节点结构体
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// 插入节点
void insertNode(TreeNode*& root, int val) {
if (root == NULL) {
root = new TreeNode(val);
return;
}
if (val < root->val) {
insertNode(root->left, val);
} else {
insertNode(root->right, val);
}
}
// 查找节点
bool searchNode(TreeNode* root, int val) {
if (root == NULL) {
return false;
}
if (val == root->val) {
return true;
} else if (val < root->val) {
return searchNode(root->left, val);
} else {
return searchNode(root->right, val);
}
}
// 删除节点
void deleteNode(TreeNode*& root, int val) {
if (root == NULL) {
return;
}
if (val < root->val) {
deleteNode(root->left, val);
} else if (val > root->val) {
deleteNode(root->right, val);
} else {
if (root->left == NULL) {
TreeNode* temp = root->right;
delete root;
root = temp;
} else if (root->right == NULL) {
TreeNode* temp = root->left;
delete root;
root = temp;
} else {
TreeNode* temp = root->right;
while (temp->left != NULL) {
temp = temp->left;
}
root->val = temp->val;
deleteNode(root->right, temp->val);
}
}
}
// 中序遍历
void inorderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
inorderTraversal(root->left);
cout << root->val << " ";
inorderTraversal(root->right);
}
int main() {
TreeNode* root = NULL;
insertNode(root, 5);
insertNode(root, 2);
insertNode(root, 8);
insertNode(root, 1);
insertNode(root, 3);
insertNode(root, 7);
insertNode(root, 9);
inorderTraversal(root);
cout << endl;
deleteNode(root, 5);
inorderTraversal(root);
cout << endl;
return 0;
}
在上面的示例代码中,我们定义了二叉搜索树节点的结构体 TreeNode
,并实现了插入节点、查找节点、删除节点和中序遍历等操作。在 insertNode
函数中,我们递归地将新节点插入到二叉搜索树中。在 searchNode
函数中,我们递归地查找目标节点。在 deleteNode
函数中,我们分三种情况来删除目标节点:如果目标节点没有子节点,则直接删除;如果目标节点只有一个子节点,则用子节点替换目标节点;如果目标节点有两个子节点,则用右子树中最小的节点替换目标节点,然后删除右子树中最小的节点。
最后,我们使用 inorderTraversal
函数来中序遍历这个二叉搜索树,并输出遍历结果。在本例中,我们先插入了七个节点,然后删除了根节点,最后再次中序遍历二叉搜索树。运行结果如下:
1 2 3 5 7 8 9
1 2 3 7 8 9
平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树,它保证了树的左右子树的高度差不超过1,从而使得树的高度始终保持在O(log n)级别。这种平衡性质使得平衡二叉树在插入、删除、查找等操作上具有更高的效率。
平衡二叉树有多种实现方式,其中最常见的是AVL树和红黑树。AVL树是一种严格平衡的二叉搜索树,它的左右子树高度差不超过1,插入和删除节点时需要旋转来维护平衡性。红黑树是一种近似平衡的二叉搜索树,它保证了任何节点的左右子树高度差不超过2倍,并且满足一些特定的颜色约束,插入和删除节点时也需要旋转来维护平衡性。
平衡二叉树的应用非常广泛,例如在数据库中用于索引、排序和快速查找等操作,还可以用于实现集合、映射、优先队列等数据结构。平衡二叉树还可以用于解决某些算法问题,例如在计算几何中用于寻找最近邻点对、在字符串匹配中用于构建后缀树等。
下面是平衡二叉树的C++实现。
首先定义平衡二叉树的节点结构体:
```c++
struct TreeNode {
int val;
int height;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), height(1), left(NULL), right(NULL) {}
};
```
其中,val表示节点的值,height表示节点的高度,left和right分别指向节点的左右子树。
接下来定义平衡二叉树类:
```c++
class AVLTree {
public:
AVLTree();
~AVLTree();
void insert(int val);
void remove(int val);
bool search(int val);
private:
TreeNode *root;
int getHeight(TreeNode *node);
int getBalanceFactor(TreeNode *node);
TreeNode *rotateLeft(TreeNode *node);
TreeNode *rotateRight(TreeNode *node);
TreeNode *rotateLeftRight(TreeNode *node);
TreeNode *rotateRightLeft(TreeNode *node);
TreeNode *insertNode(TreeNode *node, int val);
TreeNode *removeNode(TreeNode *node, int val);
TreeNode *findMinNode(TreeNode *node);
};
```
其中,insert、remove和search分别表示插入、删除和查找操作,getHeight用来获取节点的高度,getBalanceFactor用来计算节点的平衡因子,rotateLeft、rotateRight、rotateLeftRight和rotateRightLeft分别表示左旋、右旋、左右旋和右左旋操作,insertNode用来插入节点,removeNode用来删除节点,findMinNode用来查找以node节点为根的子树中最小的节点。
接下来是平衡二叉树的实现:```c++
AVLTree::AVLTree() {
root = NULL;
}
AVLTree::~AVLTree() {
while (root) {
removeNode(root, root->val);
}
}
int AVLTree::getHeight(TreeNode *node) {
return node ? node->height : 0;
}
int AVLTree::getBalanceFactor(TreeNode *node) {
return node ? getHeight(node->left) - getHeight(node->right) : 0;
}
TreeNode *AVLTree::rotateLeft(TreeNode *node) {
TreeNode *rightNode = node->right;
node->right = rightNode->left;
rightNode->left = node;
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
rightNode->height = max(getHeight(rightNode->left), getHeight(rightNode->right)) + 1;
return rightNode;
}
TreeNode *AVLTree::rotateRight(TreeNode *node) {
TreeNode *leftNode = node->left;
node->left = leftNode->right;
leftNode->right = node;
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
leftNode->height = max(getHeight(leftNode->left), getHeight(leftNode->right)) + 1;
return leftNode;
}
TreeNode *AVLTree::rotateLeftRight(TreeNode *node) {
node->left = rotateLeft(node->left);
return rotateRight(node);
}
TreeNode *AVLTree::rotateRightLeft(TreeNode *node) {
node->right = rotateRight(node->right);
return rotateLeft(node);
}
TreeNode *AVLTree::insertNode(TreeNode *node, int val) {
if (!node) {
return new TreeNode(val);
}
if (val < node->val) {
node->left = insertNode(node->left, val);
} else if (val > node->val) {
node->right = insertNode(node->right, val);
} else {
return node;
}
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
int balanceFactor = getBalanceFactor(node);
if (balanceFactor > 1 && val < node->left->val) {
return rotateRight(node);
} else if (balanceFactor < -1 && val > node->right->val) {
return rotateLeft(node);
} else if (balanceFactor > 1 && val > node->left->val) {
return rotateLeftRight(node);
} else if (balanceFactor < -1 && val < node->right->val) {
return rotateRightLeft(node);
}
return node;
}
void AVLTree::insert(int val) {
root = insertNode(root, val);
}
TreeNode *AVLTree::findMinNode(TreeNode *node) {
while (node->left) {
node = node->left;
}
return node;
}
TreeNode *AVLTree::removeNode(TreeNode *node, int val) {
if (!node) {
return node;
}
if (val < node->val) {
node->left = removeNode(node->left, val);
} else if (val > node->val) {
node->right = removeNode(node->right, val);
} else {
if (!node->left || !node->right) {
TreeNode *temp = node->left ? node->left : node->right;
if (!temp) {
temp = node;
node = NULL;
} else {
*node = *temp;
}
delete temp;
} else {
TreeNode *temp = findMinNode(node->right);
node->val = temp->val;
node->right = removeNode(node->right, temp->val);
}
}
if (!node) {
return node;
}
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
int balanceFactor = getBalanceFactor(node);
if (balanceFactor > 1 && getBalanceFactor(node->left) >= 0) {
return rotateRight(node);
} else if (balanceFactor > 1 && getBalanceFactor(node->left) < 0) {
return rotateLeftRight(node);
} else if (balanceFactor < -1 && getBalanceFactor(node->right) <= 0) {
return rotateLeft(node);
} else if (balanceFactor < -1 && getBalanceFactor(node->right) > 0) {
return rotateRightLeft(node);
}
return node;
}
void AVLTree::remove(int val) {
root = removeNode(root, val);
}
bool AVLTree::search(int val) {
TreeNode *node = root;
while (node) {
if (val < node->val) {
node = node->left;
} else if (val > node->val) {
node = node->right;
} else {
return true;
}
}
return false;
}
```
其中,insertNode和removeNode分别表示插入和删除节点的递归函数,findMinNode用来查找最小节点。在插入和删除节点时,需要对节点进行旋转来保持平衡。当节点的平衡因子大于1时,需要进行右旋、左旋、左右旋和右左旋操作。
最后,我们可以编写测试代码来测试平衡二叉树的功能:
```c++
int main() {
AVLTree tree;
tree.insert(5);
tree.insert(2);
tree.insert(1);
tree.insert(4);
tree.insert(9);
tree.insert(8);
tree.insert(10);
tree.remove(9);
cout << tree.search(9) << endl;
cout << tree.search(8) << endl;
return 0;
}
```
输出结果为:
```
0
1
```
说明平衡二叉树的功能实现正确。
红黑树是一种自平衡二叉查找树,它的特点是每个节点要么是红色,要么是黑色。同时满足以下几个条件:
1. 根节点是黑色的。
2. 每个叶子节点都是黑色的空节点(NIL节点)。
3. 如果一个节点是红色的,则它的两个子节点都是黑色的。
4. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。
由于红黑树是自平衡的,所以在插入或删除节点时会自动调整树的结构,以保持树的平衡性。
红黑树的应用非常广泛,例如在STL中的map和set就是基于红黑树实现的。它还可以用于实现高效的动态数据结构,如区间树、B树等。
以下是一个简单的红黑树的C++代码实现:```c++
#include
using namespace std;
enum Color { RED, BLACK };
class Node {
public:
int key;
Color color;
Node* left, * right, * parent;
Node(int key) {
this->key = key;
color = RED;
left = right = parent = nullptr;
}
};
class RedBlackTree {
private:
Node* root;
void rotateLeft(Node*&);
void rotateRight(Node*&);
void fixViolation(Node*&);
public:
RedBlackTree() { root = nullptr; }
void insert(int);
void inorder();
};
void RedBlackTree::insert(int key) {
Node* node = new Node(key);
root = insertBST(root, node);
fixViolation(node);
}
void RedBlackTree::inorder() {
inorderHelper(root);
}
void RedBlackTree::rotateLeft(Node*& node) {
Node* rightChild = node->right;
node->right = rightChild->left;
if (node->right != nullptr)
node->right->parent = node;
rightChild->parent = node->parent;
if (node->parent == nullptr)
root = rightChild;
else if (node == node->parent->left)
node->parent->left = rightChild;
else
node->parent->right = rightChild;
rightChild->left = node;
node->parent = rightChild;
}
void RedBlackTree::rotateRight(Node*& node) {
Node* leftChild = node->left;
node->left = leftChild->right;
if (node->left != nullptr)
node->left->parent = node;
leftChild->parent = node->parent;
if (node->parent == nullptr)
root = leftChild;
else if (node == node->parent->left)
node->parent->left = leftChild;
else
node->parent->right = leftChild;
leftChild->right = node;
node->parent = leftChild;
}
void RedBlackTree::fixViolation(Node*& node) {
Node* parent = nullptr;
Node* grandParent = nullptr;
while (node != root && node->color == RED && node->parent->color == RED) {
parent = node->parent;
grandParent = node->parent->parent;
if (parent == grandParent->left) {
Node* uncle = grandParent->right;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
}
else {
if (node == parent->right) {
rotateLeft(parent);
node = parent;
parent = node->parent;
}
rotateRight(grandParent);
swap(parent->color, grandParent->color);
node = parent;
}
}
else {
Node* uncle = grandParent->left;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
}
else {
if (node == parent->left) {
rotateRight(parent);
node = parent;
parent = node->parent;
}
rotateLeft(grandParent);
swap(parent->color, grandParent->color);
node = parent;
}
}
}
root->color = BLACK;
}
int main() {
RedBlackTree tree;
tree.insert(7);
tree.insert(3);
tree.insert(18);
tree.insert(10);
tree.insert(22);
tree.insert(8);
tree.insert(11);
tree.insert(26);
tree.inorder();
return 0;
}
```
这里只实现了插入操作和中序遍历操作,其他操作可以类似地实现。
B树和B+树是一种数据结构,用于实现磁盘存储的索引。它们可以有效地支持范围查询和顺序遍历,对于大规模数据的管理和查询非常有用。
B树和B+树的区别在于,B树的每个节点都包含关键字和指向下一级节点的指针,而B+树的每个节点只包含关键字和指向叶子节点的指针。B+树的叶子节点形成了一个有序链表,方便范围查询和顺序遍历。
下面是一个简单的B+树的代码示例:```cpp
#include
#include
using namespace std;
const int M = 4; // B+树的阶数,即每个节点最多包含M个关键字
struct Node {
vector keys; // 关键字
vector children; // 子节点指针
bool is_leaf; // 是否为叶子节点
Node* next; // 指向下一个叶子节点的指针
Node() {
is_leaf = true;
next = NULL;
}
};
class BPlusTree {
public:
BPlusTree();
~BPlusTree();
void insert(int key);
void remove(int key);
bool search(int key);
void print();
private:
Node* root;
void insert(Node* node, int key);
void split(Node* node);
void remove(Node* node, int key);
void merge(Node* node);
bool search(Node* node, int key);
void print(Node* node);
};
BPlusTree::BPlusTree() {
root = NULL;
}
BPlusTree::~BPlusTree() {
// TODO: 释放内存
}
void BPlusTree::insert(int key) {
if (root == NULL) {
root = new Node();
root->keys.push_back(key);
} else {
insert(root, key);
}
}
void BPlusTree::insert(Node* node, int key) {
if (node->is_leaf) {
node->keys.push_back(key);
sort(node->keys.begin(), node->keys.end());
if (node->keys.size() > M) {
split(node);
}
} else {
int i;
for (i = 0; i < node->keys.size(); i++) {
if (key < node->keys[i]) {
break;
}
}
insert(node->children[i], key);
}
}
void BPlusTree::split(Node* node) {
Node* new_node = new Node();
new_node->is_leaf = true;
new_node->next = node->next;
node->next = new_node;
int mid = node->keys.size() / 2;
for (int i = mid; i < node->keys.size(); i++) {
new_node->keys.push_back(node->keys[i]);
}
node->keys.erase(node->keys.begin() + mid, node->keys.end());
if (node == root) {
root = new Node();
root->keys.push_back(new_node->keys[0]);
root->children.push_back(node);
root->children.push_back(new_node);
node->is_leaf = false;
new_node->is_leaf = false;
} else {
Node* parent = node->children.back();
parent->keys.push_back(new_node->keys[0]);
sort(parent->keys.begin(), parent->keys.end());
parent->children.push_back(new_node);
new_node->is_leaf = node->is_leaf;
if (parent->keys.size() > M) {
split(parent);
}
}
}
void BPlusTree::remove(int key) {
if (root == NULL) {
return;
}
remove(root, key);
}
void BPlusTree::remove(Node* node, int key) {
if (node->is_leaf) {
for (int i = 0; i < node->keys.size(); i++) {
if (node->keys[i] == key) {
node->keys.erase(node->keys.begin() + i);
if (node->keys.size() < (M + 1) / 2 && node != root) {
merge(node);
}
break;
}
}
} else {
int i;
for (i = 0; i < node->keys.size(); i++) {
if (key < node->keys[i]) {
break;
}
}
remove(node->children[i], key);
}
}
void BPlusTree::merge(Node* node) {
Node* parent = node->children.back();
Node* sibling;
int i;
for (i = 0; i < parent->children.size(); i++) {
if (parent->children[i] == node) {
sibling = parent->children[i - 1];
break;
}
}
if (sibling->keys.size() + node->keys.size() <= M) {
for (int j = 0; j < node->keys.size(); j++) {
sibling->keys.push_back(node->keys[j]);
}
parent->keys.erase(parent->keys.begin() + i - 1);
parent->children.erase(parent->children.begin() + i);
delete node;
if (parent == root && parent->children.size() == 1) {
root = parent->children[0];
delete parent;
} else if (parent->keys.size() < (M + 1) / 2 && parent != root) {
merge(parent);
}
}
}
bool BPlusTree::search(int key) {
return search(root, key);
}
bool BPlusTree::search(Node* node, int key) {
if (node == NULL) {
return false;
}
if (node->is_leaf) {
for (int i = 0; i < node->keys.size(); i++) {
if (node->keys[i] == key) {
return true;
}
}
return false;
} else {
int i;
for (i = 0; i < node->keys.size(); i++) {
if (key < node->keys[i]) {
break;
}
}
return search(node->children[i], key);
}
}
void BPlusTree::print() {
print(root);
}
void BPlusTree::print(Node* node) {
if (node == NULL) {
return;
}
if (node->is_leaf) {
for (int i = 0; i < node->keys.size(); i++) {
cout << node->keys[i] << " ";
}
cout << endl;
} else {
for (int i = 0; i < node->children.size(); i++) {
print(node->children[i]);
if (i < node->keys.size()) {
cout << node->keys[i] << " ";
}
}
cout << endl;
}
}
int main() {
BPlusTree tree;
tree.insert(1);
tree.insert(3);
tree.insert(5);
tree.insert(7);
tree.insert(9);
tree.insert(2);
tree.insert(4);
tree.insert(6);
tree.insert(8);
tree.insert(10);
tree.remove(5);
tree.print(); // 1 2 3 4 6 7 8 9 10
cout << tree.search(5) << endl; // 0
cout << tree.search(6) << endl; // 1
return 0;
}
```
上面的代码实现了B+树的插入、删除、查找和打印功能。在插入时,如果一个节点的关键字数量超过了阶数M,就需要进行分裂操作。在删除时,如果一个节点的关键字数量小于了阶数(M+1)/2,就需要进行合并操作。在查找时,从根节点开始遍历,如果遇到叶子节点就按顺序查找关键字。在打印时,按层遍历节点并输出关键字。
B树和B+树的应用非常广泛,比如数据库索引和文件系统索引等。它们可以加快数据的查找和排序,提高数据的访问效率。
Trie树,也叫字典树或前缀树,是一种树形数据结构,它是一种哈希树的变种。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
Trie树的基本性质如下:
1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2. 从根节点到某一节点,路径上经过的字符连接起来,即为该节点对应的字符串。
3. 每个节点的所有子节点包含的字符都不相同。
Trie树的应用:
1. 字符串检索:Trie树可以在一组字符串中快速查找某个字符串是否存在。
2. 前缀匹配:Trie树可以在一组字符串中快速查找以某个前缀开头的所有字符串。
3. 自动补全:Trie树可以在一组字符串中快速查找以某个前缀开头的所有字符串,并自动补全该前缀。
4. IP路由:Trie树可以用来实现IP路由表。
C++代码示例:
以下是Trie树的C++代码示例,包括插入字符串和查询字符串的函数:```cpp
#include
#include
using namespace std;
const int MAXN = 100010;
const int MAXM = 26;
struct TrieNode {
int cnt; // 记录该节点被访问的次数
TrieNode* next[MAXM]; // 指向下一个节点的指针
TrieNode() {
cnt = 0;
memset(next, 0, sizeof(next));
}
};
class Trie {
public:
Trie() {
root = new TrieNode();
}
void insert(string word) {
TrieNode* p = root;
for (int i = 0; i < word.length(); i++) {
int index = word[i] - 'a';
if (!p->next[index]) {
p->next[index] = new TrieNode();
}
p = p->next[index];
}
p->cnt++;
}
int query(string word) {
TrieNode* p = root;
for (int i = 0; i < word.length(); i++) {
int index = word[i] - 'a';
if (!p->next[index]) {
return 0;
}
p = p->next[index];
}
return p->cnt;
}
private:
TrieNode* root;
};
int main() {
Trie tree;
tree.insert("apple");
tree.insert("app");
tree.insert("banana");
tree.insert("orange");
cout << tree.query("apple") << endl; // 输出 1
cout << tree.query("app") << endl; // 输出 1
cout << tree.query("banana") << endl; // 输出 1
cout << tree.query("orange") << endl; // 输出 1
cout << tree.query("pear") << endl; // 输出 0
return 0;
}
```
堆是一种特殊的树形数据结构,它满足以下两个性质:
1. 堆是一颗完全二叉树;
2. 堆中每个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。
根据第二个性质,我们可以将堆分为最大堆和最小堆。在最大堆中,每个节点的值都大于等于子节点的值;在最小堆中,每个节点的值都小于等于子节点的值。
堆的应用:
1. 堆排序:堆排序是一种高效的排序算法,它的时间复杂度为O(nlogn)。
2. 优先队列:堆可以用来实现优先队列,每次取出堆顶元素即可得到优先级最高的元素。
3. 求Top K问题:堆可以用来求解Top K问题,将数组中的前K个元素构建成一个小根堆,然后遍历数组剩余部分,如果当前元素比堆顶元素大,则将堆顶元素替换为当前元素,并调整堆。
C++代码示例:
以下是最大堆和最小堆的C++代码示例:```cpp
#include
#include
#include
using namespace std;
// 最大堆
void max_heap() {
priority_queue q; // 默认是大根堆
q.push(3);
q.push(1);
q.push(4);
q.push(1);
q.push(5);
while (!q.empty()) {
cout << q.top() << " ";
q.pop();
}
cout << endl;
}
// 最小堆
void min_heap() {
priority_queue, greater> q; // 小根堆
q.push(3);
q.push(1);
q.push(4);
q.push(1);
q.push(5);
while (!q.empty()) {
cout << q.top() << " ";
q.pop();
}
cout << endl;
}
int main() {
max_heap(); // 输出 5 4 3 1 1
min_heap(); // 输出 1 1 3 4 5
return 0;
}
```