提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
二叉树是计算机科学中最基础且重要的数据结构之一,广泛应用于算法设计、数据存储和系统优化等领域。
一、二叉树是什么?
二叉树(Binary Tree)是计算机科学中最基础且重要的非线性数据结构之一。它是由结点(Node)组成的层次结构,每个结点最多有两个子结点,分别称为 左子结点(Left Child)和右子结点(Right Child)。
二叉树的基本概念
- 根结点(Root):位于树顶端的结点,没有父结点,是整个二叉树的起点。
- 子结点(Child):一个结点的直接后继结点称为子结点。
- 父结点(Parent):一个结点的直接前驱结点称为父结点。
- 叶结点(Leaf):没有子结点的结点,也称为终端结点。
- 度(Degree):一个结点拥有的子结点数目称为度(二叉树的度最大为2)。
- 深度(Depth):从根结点到该结点的最长路径上的边数。
- 高度(Height):从该结点到最深叶结点的最长路径上的边数。
二叉树的常见类型
- 满二叉树(Full Binary Tree):每个结点要么是叶结点,要么恰好有两个子结点。
- 完全二叉树(Complete Binary Tree):除了最后一层外,其他各层的结点数都达到最大;最后一层的结点都连续集中在最左边。
- 平衡二叉树(Balanced Binary Tree):任意结点的左右子树的高度差不超过1(如AVL树)。
- 二叉搜索树(Binary Search Tree, BST):对于树中的每个结点,其左子树所有结点的值都小于该结点的值,右子树所有结点的值都大于该结点的值。
- 线索二叉树(Threaded Binary Tree):利用空指针存储前驱或后继结点信息,以提高遍历效率。
二叉树的基本操作
- 遍历(Traversal) :
- 先序遍历(Pre-order):根→左→右
- 中序遍历(In-order):左→根→右
- 后序遍历(Post-order):左→右→根
- 层次遍历(Level-order):按层次从上到下,从左到右
- 插入(Insertion):在适当位置添加新结点
- 删除(Deletion):移除指定结点并保持二叉树性质
- 查找(Search):在树中查找特定值的结点
- 计算高度/深度:确定树或子树的高度/深度
二叉树的应用场景
- 文件系统:目录结构通常采用树形结构表示
- 数据库索引:B树、B+树等索引结构基于二叉树扩展
- 表达式求值:算术表达式可以用表达式树表示
- 决策树:机器学习中的决策树算法
- 哈夫曼编码:用于数据压缩的哈夫曼树
- 游戏AI:游戏中的决策树和状态空间搜索
二叉树的特点
- 非线性结构:相比线性结构(如数组、链表),数据关系更复杂
- 递归定义:每个子树本身也是一棵二叉树
- 高效查找:平衡二叉搜索树的查找时间复杂度为O(log n)
- 内存效率:相比普通树结构,二叉树每个结点最多两个指针,内存占用更少
二叉树作为基础数据结构,为理解更复杂的树结构(如红黑树、B树等)奠定了基础,在算法设计和系统实现中有着广泛的应用。
二、相关代码实现
初始化二叉树的节点
cpp
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
//初始化二叉树节点
三种遍历二叉树的方式
cpp
//二叉树前序遍历
void PreOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
printf("%d ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
// 二叉树中序遍历
void InOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PreOrder(root->left);
printf("%d ", root->data);
PreOrder(root->right);
}
// 二叉树后序遍历
void PostOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PreOrder(root->left);
PreOrder(root->right);
printf("%d ", root->data);
}
计算二叉树节点的个数
cpp
//计算树的节点
int TreeSize(BTNode* root)
{
return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
计算树的叶子节点的个数
cpp
//计算树的叶子节点的个数
int TreeNodeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left==NULL&&root->right==NULL)
{
return 1;
}
return TreeNodeSize(root->left) + TreeNodeSize(root->right);
}
//首先叶子节点的个数=左子树叶子节点的个数+右子树叶子节点的个数
//如果左子树为空并且右子树为空则为叶子节点
//当遇到空节点直接返回0
计算树的高度
cpp
//二叉树的高度
int TreeHeight(BTNode* root)
{
if (root == NULL)
{
return 0;
}
int left = TreeHeight(root->left);
int right = TreeHeight(root->right);
return left > right ? left + 1 : right + 1;
}
//写出递推公式树的高度=max(左子树的高度,右子树的高度)+1
单值二叉树
cpp
bool isUnivalTree(struct TreeNode* root) {
if(root==NULL)
{
return true;
}
if(root->right)
{
if(root->right->val!=root->val||!isUnivalTree(root->right))
return false;
}
if(root->left)
{
if(root->left->val!=root->val||!isUnivalTree(root->left))
return false;
}
return true;
}
/*一棵树的所有节点都有相同的值,当且仅当对于树上的每一条边的两个端点,它们都有相同的值(这样根据传递性,所有节点都有相同的值)。
因此,我们可以对树进行一次深度优先搜索。当搜索到节点 x 时,我们检查 x 与 x 的每一个子节点之间的边是否满足要求。例如对于左子节点而言,如果其存在并且值与 x 相同,那么我们继续向下搜索该左子节点;如果值与 x 不同,那么我们直接返回 False。
*/
cs
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
// 1. 两个节点都为空:相同
if (p == NULL && q == NULL)
return true;
// 2. 一个为空、一个不为空:不同
if (p == NULL || q == NULL)
return false;
// 3. 节点值不同:不同
if (p->val != q->val)
return false;
// 4. 递归比较左右子树(不管是否为空)
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
总结
一些相关二叉树的基本知识和一些简单的力扣题目