
本节围绕二叉树的常见 OJ 题展开,涵盖前序遍历、单值二叉树判定和对称二叉树判定三类问题,帮助建立递归操作二叉树的思维方式。
大部分人学算法都是这个循环:听懂 → 过段时间忘光 → 重新看懂 → 慢慢内化,能力一点点涨。

二叉树前序遍历
题目要求返回一个指针,通过指针访问数组元素。显然需要创建一个指针作为数组的首地址。returnSize 是输出参数(指针),判题工具会根据这个形参的值来判断结果是否正确——它作为数组下标,将遍历好的节点值一一放入目标数组。
LeetCode 题目里的形参都有它具体的意思,题做多了就认得了。

void dfs(struct TreeNode* node, int* result, int* returnSize){
if(node == NULL){
return;
}
result[(*returnSize)++] = node->val;
dfs(node->left, result, returnSize);
dfs(node->right, result, returnSize);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
int* result =(int*)malloc(sizeof(int) * 100);
*returnSize = 0;
dfs(root, result, returnSize);
return result;
}
具体讲解:
– 因为是数组要用到指针,所以需要 malloc(没 malloc 该指针只能储存一个数据)
– 利用 returnSize 作为下标将二叉树的节点一一插入,所以解引用赋值为 0
– dfs 的形参包含二叉树节点、数组和下标,根据前序排列将数据插入数组
二叉树的题型一般都会考虑到当首节点为 NULL 时直接 return。这就是前序遍历的方法 ELR(根-左-右):

result[(*returnSize)++] = node->val;
dfs(node->left, result, result, returnSize);
dfs(node->right, result, returnSize);
优先级注意:
(*returnSize)++若是没括号就是给指针加加。*returnSize++先加加再解引用。++*returnSize先解引用再加加。
中序遍历(LRA)和后序遍历(LRA)的代码结构类似,只改变插入顺序:

中序遍历 LRA(左-根-右):
dfs(node->left, result, returnSize);
result[(*returnSize)++] = node->val;
dfs(node->right, result, returnSize);
后序遍历 LRA(左-右-根):

dfs(node->left, result, returnSize);
dfs(node->right, result, returnSize);
result[(*returnSize)++] = node->val;
sizeof(int) * 100是因为题目要求二叉树节点不超过 100 个。
单值二叉树

判断一棵二叉树是否为单值二叉树,即所有节点的值都相同。思路是递归检查每个节点的左右子节点是否等于根节点的值。
bool isUnivalTree(struct TreeNode* root) {
if(root == NULL){
return true;
}
if(root->left && root->left->val != root->val){
return false;
}
if(root->right && root->right->val != root->val){
return false;
}
return isUnivalTree(root->left) && isUnivalTree(root->right);
}
- 头节点为
NULL即视为单值二叉树,返回true - 判断目标节点的左右节点是否等于头节点的值
- 用递归遍历左右两树杈是否符合规则
&&的作用:只有左右两边为真才为真。利用递归函数和&&,只要有一个不符合规则就会返回false
补充
||:两个为真才为真,两个为假才为假,一假一真为真。
递归的关键是看最后一步 return 的返回值,然后倒推上一个函数的返回值。
对称二叉树
判断一棵二叉树是否对称,需要比较左子树和右子树是否镜像对称。
bool check(struct TreeNode* left, struct TreeNode* right){
if(left == NULL && right == NULL){
return true;
}
if(left == NULL || right == NULL){
return false;
}
if(left->val != right->val){
return false;
}
return check(left->left, right->right) && check(left->right, right->left);
}
bool isSymmetric(struct TreeNode* root) {
if(root == NULL){
return true;
}
return check(root->left, root->right);
}
- 头节点为
NULL即为对称二叉树,返回true check函数的形参为左右节点指针left == NULL && right == NULL:当只有一个节点时为对称二叉树返回true;当全对比完后说明符合规则也返回trueleft == NULL || right == NULL:只有一个为空说明不对称,返回false- 核心比较:
check(left->left, right->right) && check(left->right, right->left)——左子树的左与右子树的右比较,左子树的右与右子树的左比较。这样递归就可以符合对称二叉树的规则