数据结构与算法:树(Tree)精讲

“ 初音之始,响彻未来,终是末世之花 ” ——初音未来
(ノ▽`*)ノ[换头像啦♪]=з=з=з
窝换了新主题傲 ~ 写篇博客看看效果,想要涨粉喵 =(´ω`*)=3 3 3
前言:
好的开始啦,这是一篇关于数据结构“树”的详细讲解,并辅以C++实现的博文。
文章结构清晰,从概念到实现,逐步深入,希望能帮助你更好地理解树这种重要的数据结构。
数据结构详解--树(C++实现)
树(Tree) 是一种非常重要的非线性数据结构,它在现实世界和计算机科学中有着广泛的应用。
例如:文件系统、数据库索引、DOM树、组织结构图等。与线性结构(如数组、链表)不同,树能够高效地表示具有层次关系的数据~
本文将深入浅出地讲解树的核心概念、遍历方式,并使用C++实现一个基础的二叉树,及其常见操作。
一. 树的基本概念
首先,我们来了解一些关于树的核心术语:
· 节点(Node): 树的基本构成单位,包含数据项及指向其他节点的分支。
· 根节点(Root): 位于树顶端的节点,是唯--个没有父节点的节点。
· 父节点(Parent):一个节点如果有子节点,则该节点是其子节点的父节点。
· 子节点(Child):一个节点的直接后继节点。
· 兄弟节点(Sibling):具有相同父节点的节点互称为兄弟节点。
· 叶节点(Leaf):没有子节点的节点,也称为终端节点。子树(Subtree):一个节点及其所有后代节点构成的集台。
·节点的度(Degree) :一个节点拥有的子节点数。
·树的度:树中所有节点的度的最大值。
·深度(Depth):从根节点到该节点所经过的边的个数。
·高度(Height):从该节点到最远叶节点所经过的边的个数。树的高度是根节点的高度。
二、二叉树(Binary Tree)
二叉树是树结构中最常用的一种。它的特点是每个节点最多有两个子节点,通常称为左子节点(LeftChild)和右子节点(Right Child)
1.二叉树的C++节点定义
我们使用结构体来定义一个简单的二叉树节点:
#include <iostream>// 定义二叉树节点
struct TreeNode {int val; // 节点存储的数据TreeNode* left; // 指向左子节点的指针TreeNode* right; // 指向右子节点的指针// 构造函数TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
2.二叉树的遍历
遍历是二叉树最基本也是最重要的操作,指的是按照某种顺序访问树中的每一个节点,且每个节点仅被访问一次。主要有四种方式:
(1)前序遍历(Preorder Traversal)
顺序:根→左子树 →右子树
应用:常用于复制整个树的结构。
void preorderTraversal(TreeNode* root) {if (root == nullptr) return; // 递归基:如果节点为空,则返回std::cout << root->val << " "; // 访问根节点preorderTraversal(root->left); // 递归遍历左子树preorderTraversal(root->right); // 递归遍历右子树
}
(2)中序遍历(Inorder Traversal)
顺序:左子树 → 根 → 右子树
应用:在二叉搜索树(BST)中,中序遍历会得到一个升序序列。
void inorderTraversal(TreeNode* root) {if (root == nullptr) return;inorderTraversal(root->left); // 递归遍历左子树std::cout << root->val << " "; // 访问根节点inorderTraversal(root->right); // 递归遍历右子树
}
(3)后序遍历(Postorder Traversal)
顺序:左子树→右子树→根
应用:常用于释放树的内存,因为先释放子节点再释放父节点是安全的。
void postorderTraversal(TreeNode* root) {if (root == nullptr) return;postorderTraversal(root->left); // 递归遍历左子树postorderTraversal(root->right); // 递归遍历右子树std::cout << root->val << " "; // 访问根节点
}
(4)层序遍历(LevelOrder Traversal)
顺序:从上到下、从左到右逐层访问节点。
应用:求树的宽度、按层级处理数据。
实现:需要借助队列(Queue)这种数据结构。
#include <queue>void levelOrderTraversal(TreeNode* root) {if (root == nullptr) return;std::queue<TreeNode*> q;q.push(root);while (!q.empty()) {TreeNode* current = q.front();q.pop();std::cout << current->val << " ";// 将当前节点的左子节点和右子节点入队if (current->left != nullptr) q.push(current->left);if (current->right != nullptr) q.push(current->right);}
}
三、完整的C++示例代码
下面是一个完整的程序,演示如何构建一个简单的二又树并进行各种遍历。
#include <iostream>
#include <queue>struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};class BinaryTree {
public:TreeNode* root;// 一个简单的创建二叉树的方法(手动构建)BinaryTree() {/* 构建如下结构的二叉树:1/ \\2 3/ \\4 5*/root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);std::cout << "二叉树创建成功!" << std::endl;}// 前序遍历void preorder(TreeNode* node) {if (node == nullptr) return;std::cout << node->val << " ";preorder(node->left);preorder(node->right);}// 中序遍历void inorder(TreeNode* node) {if (node == nullptr) return;inorder(node->left);std::cout << node->val << " ";inorder(node->right);}// 后序遍历void postorder(TreeNode* node) {if (node == nullptr) return;postorder(node->left);postorder(node->right);std::cout << node->val << " ";}// 层序遍历void levelOrder() {if (root == nullptr) return;std::queue<TreeNode*> q;q.push(root);while (!q.empty()) {TreeNode* current = q.front();q.pop();std::cout << current->val << " ";if (current->left != nullptr) q.push(current->left);if (current->right != nullptr) q.push(current->right);}}// 释放二叉树内存(后序遍历方式)void deleteTree(TreeNode* node) {if (node == nullptr) return;deleteTree(node->left);deleteTree(node->right);std::cout << "删除节点: " << node->val << std::endl;delete node;}~BinaryTree() {std::cout << "\\n开始销毁二叉树..." << std::endl;deleteTree(root);}
};int main() {BinaryTree tree;std::cout << "前序遍历: ";tree.preorder(tree.root);std::cout << std::endl;std::cout << "中序遍历: ";tree.inorder(tree.root);std::cout << std::endl;std::cout << "后序遍历: ";tree.postorder(tree.root);std::cout << std::endl;std::cout << "层序遍历: ";tree.levelOrder();std::cout << std::endl;return 0;// tree的析构函数会自动调用,释放内存
}
输出结果:
二叉树创建成功!
前序遍历: 1 2 4 5 3
中序遍历: 4 2 5 1 3
后序遍历: 4 5 2 3 1
层序遍历: 1 2 3 4 5开始销毁二叉树...
删除节点: 4
删除节点: 5
删除节点: 2
删除节点: 3
删除节点: 1
四、树的更多类型
除了普通的二又树,还有一些非常重要且实用的变体:
1. 二叉搜索树(BST):对于任意节点,其左子树所有节点的值都小于它,右子树所有节点的值都大于它。这使得查找、插入、删除操作非常高效(平均时间复杂度O(log n))。
2. 平衡二叉搜索树(AVL树、红黑树)普通的BST在极端情况下会退化成链表。平衡树通过旋转操作自动保持树的平衡,确保操作效率稳定在O(logn)。std::map和 std::set 在C++中通常用红黑树实现。
3. 堆(Heap):一种特殊的完全二叉树,常用于实现优先队列和堆排序。
4. Trie树(字典树):-专门用于处理字符串集合,常用于搜索引擎的自动补全、拼写检查等。
总结
树是一种功能强大且灵活的数据结构,它为我们处理层次化、关联性数据提供了理想的模型。理解二叉树的基本概念、遍历方式及其C++实现,是学习更复杂树结构(如BST、AVL、B树等)的坚实基础。
希望这篇博文能帮助你打开树结构的大门!在后续的学习中可以重点关注二叉搜索树和平衡二叉树,它们是面试和实际项目中应用最广泛的树结构之一。
最后,希望看到这里的Oler们,给个点赞和关注吧,我真的很想涨粉。ヽ(`⌒´メ)ノ嗷嗷嗷~~~

