文章目录

◆ 博主名称:此生决int
大家好,欢迎来到我的博客~
⭐ 个人专栏:快速复习系列
⭐ 热门专栏:算法基础到精通系列
上期回顾
上期我们主要介绍了二叉树的顺式存储方式,堆的概念和性质,以及应用,重点介绍了向上调整算法和向下调整算法,以及堆排序!
文章概要
本文系统讲解二叉树链式结构的核心知识点与高频考点,从入门到进阶全覆盖:
✅ 基础必学:前序 / 中序 / 后序遍历、层序 BFS 遍历,彻底搞懂二叉树遍历逻辑
✅ 核心算法:节点总数 / 叶子节点数 / 树高度(含优化)/ 第 k 层节点数 / 查找指定节点,附递归实现与优化思路
✅ 高频 OJ 题:单值二叉树、相同的树、对称二叉树、二叉树创建、前序遍历 OJ 题,拆解解题思路
✅ 配套练习:二叉树相关选择题,巩固基础知识点
帮你告别二叉树递归 bug,轻松应对期末、竞赛与面试!
二叉树链式结构的实现
1 前置说明
现在大家对二叉树结构掌握还不够深入,此处手动快速创建一棵简单的二叉树,
cpp
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
BTNode* CreatBinaryTree()
{
BTNode* node1 = BuyNode(1);
BTNode* node2 = BuyNode(2);
BTNode* node3 = BuyNode(3);
BTNode* node4 = BuyNode(4);
BTNode* node5 = BuyNode(5);
BTNode* node6 = BuyNode(6);
node1->_left = node2;
node1->_right = node4;
node2->_left = node3;
node4->_left = node5;
node4->_right = node6;
return node1;
}
我们先来回顾下二叉树的概念,二叉树是:
- 空树
- 非空:根结点,根结点的左子树、根结点的右子树组成的。
说白了,树就是由根节点,左树+右树。左树又由根节点+左树+右树 。
所以,二叉树定义是递归式 的

2.二叉树的遍历⭐️⭐️
遍历是基础中的基础!!!所谓二叉树遍历是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次 。前,中,后遍历的区别就是根节点访问的先后顺序!!又称为先根遍历、中根遍历和后根遍历。
前序遍历
访问顺序:根--->左--->右
cpp
void preorder(treenode*root)
{
if(root==NULL)
return ;
//访问根节点
//例如:cout<<root->val<<endl;
cout<<root->val<<endl;
//访问左子树
preorder(root->left);
//访问右子树
preorder(root->right);
}
中序遍历
访问顺序:左--->根--->右
cpp
void inorder(treenode*root)
{
if(root==NULL)
return ;
//访问左子树
inorder(root->left);
//访问根节点
cout<<root->val<<endl;
//访问右子树
inorder(root->right);
}
后序遍历
访问顺序:左--->右--->根
cpp
void postorder(treenode*root)
{
if(root==NULL)
return ;
//访问左子树
postorder(root->left);
//访问右子树
postorder(root->right);
//访问根节点
cout<<root->val<<endl;
}
3.二叉树相关选择题
1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为( )
A ABDHECFG
B ABCDEFGH
C HDBEAFCG
D HDEBFGCA
2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为()
A E
B F
C G
D H
3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。
A adbce
B decab
C debac
D abcde
4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为
A FEDCBA
B CBAFED
C DEFCBA
D ABCDEF
答案:1,A 2,A 2,D 4,A
4.二叉树的链式题目⭐️⭐️⭐️
二叉树结点个数
int BinaryTreeSize(BTNode* root);
cpp
int TreeSize(BTNode* root)
{
return root == NULL ? 0 :
TreeSize(root->left) + TreeSize(root->right) + 1;
}
二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);
cpp
int TreeLeafSize(BTNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return TreeLeafSize(root->left)
+ TreeLeafSize(root->right);
}
二叉树的高度
cpp
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
return TreeHeight(root->left) > TreeHeight(root->right) ?
TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}
优化⭐️⭐️
cpp
int TreeHeight(BTNode* root)
{
if(!root) return 0;
int lh = TreeHeight(root->left);
int rh = TreeHeight(root->right);
return (lh > rh ? lh : rh) + 1;
}
二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
cpp
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
// 子问题
return TreeLevelKSize(root->left, k - 1)
+ TreeLevelKSize(root->right, k - 1);
}
二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
cpp
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->data == x)
return root;
BTNode* ret1 = TreeFind(root->left, x);
if (ret1)
return ret1;
BTNode* ret2 = TreeFind(root->right, x);
if (ret2)
return ret2;
return NULL;
}
5.二叉树相关算法题⭐️⭐️⭐️
单值二叉树
cpp
/**
* 解题思路:
* 单值二叉树定义为所有节点值完全相同的二叉树。
* 本题采用递归方式自顶向下判断:
* 1. 空树或只有一个节点(叶子节点)直接视为单值二叉树。
* 2. 检查当前节点与左右子节点的值是否相等(若子节点存在)。
* 3. 若任一直接子节点的值与当前节点不同,则立即返回 false。
* 4. 若当前层满足条件,则递归检查左右子树是否也都是单值二叉树。
* 5. 整个树满足单值当且仅当所有层次都通过上述检查。
*/
class Solution {
public:
bool isUnivalTree(TreeNode* root) {
// 空树认为是单值二叉树
if (root == NULL)
return true;
// 叶子节点:没有左右孩子,已经满足单值要求
if (root->left == NULL && root->right == NULL)
return true;
// 检查左孩子是否存在且值是否相等
if (root->left != NULL && root->left->val != root->val)
return false;
// 检查右孩子是否存在且值是否相等
if (root->right != NULL && root->right->val != root->val)
return false;
// 当前节点与孩子值一致,继续递归检查左右子树是否也是单值二叉树
return isUnivalTree(root->left) && isUnivalTree(root->right);
}
};
相同的树
cpp
/**
* 解题思路:
* 判断两棵二叉树是否相同,需要同时满足结构相同和节点值相同。
* 采用递归方式同步遍历两棵树:
* 1. 如果两个节点都为空,说明当前分支结构一致且无值差异,返回 true。
* 2. 如果只有一个为空,说明结构不同,返回 false。
* 3. 如果两个节点都不为空,先判断当前节点值是否相等:
* - 不相等则直接返回 false。
* - 相等则继续递归检查左子树和右子树是否分别相同。
* 4. 左右子树均相同时,两棵树才完全相同。
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
// 两个节点都为空,当前分支结构相同,返回 true
if (p == NULL && q == NULL)
return true;
// 只有一个为空,结构不同,返回 false
if (p == NULL || q == NULL)
return false;
// 当前节点值相等时,继续递归比较左右子树
if (p->val == q->val) {
// 左右子树必须同时相同,才返回 true
if ((isSameTree(p->left, q->left)) && (isSameTree(p->right, q->right)))
return true;
else
return false;
}
// 节点值不相等,直接返回 false
else
return false;
}
对称二叉树
cpp
/**
* 解题思路:
* 轴对称二叉树要求树的左子树与右子树互为镜像。
* 通过递归辅助函数同步比较两棵树是否镜像对称:
* 1. 两树都为空:对称,返回 true。
* 2. 一空一非空:不对称,返回 false。
* 3. 根节点值不等:不对称,返回 false。
* 4. 当前节点值相等时,进一步检查:
* - 左树的左孩子 与 右树的右孩子 是否镜像对称
* - 左树的右孩子 与 右树的左孩子 是否镜像对称
* 5. 二者皆对称时,说明两树整体镜像对称。
* 主函数判断 root 为空(对称)或调用辅助函数比较左右子树。
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
// 辅助函数:判断 ret1 与 ret2 是否镜像对称
bool _isSymmetric(struct TreeNode *ret1, struct TreeNode* ret2) {
// 两个节点都为空,对称
if (ret1 == NULL && ret2 == NULL)
return true;
// 只有一个为空,不对称
if (ret1 == NULL || ret2 == NULL)
return false;
// 节点值不等,不对称
if (ret1->val != ret2->val)
return false;
// 当前层对称,递归比较"错位"的子树
return (_isSymmetric(ret1->left, ret2->right) &&
_isSymmetric(ret1->right, ret2->left));
}
// 主函数:判断整棵树是否轴对称
bool isSymmetric(struct TreeNode* root) {
// 空树视为轴对称
if (root == NULL)
return true;
// 比较左子树和右子树是否镜像对称
return _isSymmetric(root->left, root->right);
}
另一棵树的子树
另一棵树的子树

cpp
/**
* 解题思路:
* 要判断 subRoot 是否是 root 的子树,可以分解为两个步骤:
* 1. 判断两棵树是否完全相同(结构和节点值均一致)。
* 2. 遍历 root 树的每一个节点,将以该节点为根的子树与 subRoot 进行"相同性"比较。
*
* 具体做法:
* - 利用辅助函数 isSameTree 判断两棵树是否完全一致。
* - 在 isSubtree 中,先比较当前 root 与 subRoot 是否相同,若相同则直接返回 true。
* - 否则,如果 root 的左子树存在,递归地在左子树中查找 subRoot;
* 如果找到则返回 true。
* - 同理,如果 root 的右子树存在,递归地在右子树中查找 subRoot;
* 如果找到则返回 true。
* - 如果当前节点、左子树、右子树中都没有找到相同的子树,则返回 false。
*
* 注意:本代码假定 subRoot 非空。若 root 为空且 subRoot 非空,最终会因没有左右子树而返回 false。
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
// 判断两棵树 p 和 q 是否完全相同
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
// 两个节点都为空,结构相同
if (p == NULL && q == NULL)
return true;
// 只有一个为空,结构不同
if (p == NULL || q == NULL)
return false;
// 节点值相等时,继续检查左右子树是否也分别相同
if (p->val == q->val) {
if ((isSameTree(p->left, q->left)) && (isSameTree(p->right, q->right)))
return true;
else
return false;
}
// 节点值不相等,树不相同
else
return false;
}
// 判断 subRoot 是否是 root 的子树
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot) {
// 先检查以 root 为根的树是否与 subRoot 完全相同
if (isSameTree(root, subRoot))
return true;
// 否则在左子树中递归寻找
if (root->left) {
if (isSubtree(root->left, subRoot))
return true;
}
// 否则在右子树中递归寻找
if (root->right) {
if (isSubtree(root->right, subRoot))
return true;
}
// 当前 root 及其左右子树均未找到,返回 false
return false;
}
二叉树的创建⭐️⭐️⭐️⭐️
cpp
/**
* 解题思路:
* 题目要求根据给定的先序遍历字符串('#' 表示空节点)建立二叉树,
* 并对该二叉树进行中序遍历输出结果。
*
* 整体分为三步:
* 1. 定义二叉树节点结构体:存储字符值、左孩子指针、右孩子指针。
* 2. 利用递归构建二叉树:
* - 用一个索引指针遍历字符串。
* - 如果当前字符为 '#',表示空树,索引后移并返回 NULL。
* - 否则创建新节点,字符赋值,索引后移;
* 然后递归构建左子树,再递归构建右子树。
* 3. 对构建好的二叉树进行中序遍历(左-根-右),打印节点值。
*/
#include <iostream>
using namespace std;
// 二叉树节点定义
struct TreeNode {
struct TreeNode* left;
struct TreeNode* right;
char val; // 节点存储的字符值
};
/**
* 根据先序字符串递归创建二叉树
* @param s 输入的先序遍历字符串
* @param pi 当前处理字符的索引指针(通过指针传递,实现跨递归修改)
* @return 新生成的二叉树节点的指针
*/
TreeNode* CreatTree(string& s, int *pi) {
// 遇到 '#' 表示空节点,索引前进并返回空指针
if (s[*pi] == '#') {
(*pi)++;
return NULL;
}
// 分配新节点
// 使用 malloc 分配内存(也可用 new)
TreeNode* ret = (TreeNode*)malloc(sizeof(TreeNode));
// 节点赋值当前字符,然后索引前进
ret->val = s[*pi];
(*pi)++;
// 递归构建左子树和右子树
ret->left = CreatTree(s, pi);
ret->right = CreatTree(s, pi);
return ret;
}
/**
* 中序遍历二叉树(左 - 根 - 右)
* @param root 当前树的根节点
*/
void Mind(TreeNode* root) {
if (root == NULL)
return;
// 遍历左子树
Mind(root->left);
// 打印当前节点值(使用 printf 保持原风格)
printf("%c ", root->val);
// 遍历右子树
Mind(root->right);
}
int main() {
string s;
cin >> s; // 读入先序遍历字符串,例如:ABC##DE#G##F###
int i = 0; // 初始化字符串索引
TreeNode* root = CreatTree(s, &i); // 构建二叉树
Mind(root); // 中序遍历并输出结果
return 0;
}
// 64 位输出建议使用 printf("%lld"),本处输出字符未涉及此项
二叉树的前序遍历OJ
cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int TreeSize(struct TreeNode* root)
{
if(root==NULL)
return 0;
return (TreeSize(root->left)+TreeSize(root->right)+1);
}
void PreOrder(struct TreeNode* root,int *arr,int *pi)
{
if(root==NULL)
return;
arr[(*pi)++]=root->val;
PreOrder(root->left,arr,pi);
PreOrder(root->right,arr,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
//if(root==NULL)
// return NULL;
*returnSize=TreeSize(root);
int *arr=(int *)realloc(arr,sizeof(int)*(*returnSize));
int i=0;
PreOrder(root,arr,&i);
return arr;
}
注意事项:
- leetcode返回数组要返回数组的大小,用的返回型参数
- 递归传的参要用pi,这样 i 才能往后加(类似计算数的节点个数那个题)
二叉树的层序遍历(BFS)
cpp
void TreeLevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
printf("%d ", front->data);
if (front->left)
QueuePush(&q, front->left);
if (front->right)
QueuePush(&q, front->right);
}
QueueDestroy(&q);
}
下期预告
OK,今天的博客先分享到这里,我们上一篇博客学习了堆排序,想不想学习更多的排序算法?下一期我们将一起学习数据结构的最后一节------七大排序算法!!!
结语
** 本文到此结束,欢迎各位在评论区探讨交流。需要快速复盘、精简学习内容的朋友,别忘了订阅我的快速复习专栏哦,主打专注整合学习中的精华,我们一起加油吧!**



