

层次遍历
cpp
class Solution {
public:
bool isSymmetric(TreeNode* root) {
// 如果根节点为空,空树被认为是镜像对称的
if (!root) return true;
// 创建一个队列用于层序遍历,存储待处理的树节点
queue<TreeNode*> que;
// 将根节点加入队列,开始层序遍历
que.push(root);
// 当队列不为空时,继续处理(表示还有节点未遍历)
while (!que.empty()) {
// 记录当前层的节点数量(重要:需要在循环前固定大小)
int size = que.size();
// 创建一个数组用于存储当前层所有节点的值(包括空节点)
vector<int> levelValues;
// 遍历当前层的所有节点
// 注意:使用固定size,因为循环中会向队列添加子节点,que.size()会变化
for (int i = 0; i < size; i++) {
// 从队列头部取出节点
TreeNode* node = que.front();
que.pop(); // 弹出已处理的节点
// 如果当前节点不为空
if (node) {
// 将当前节点的值加入当前层的数组
levelValues.push_back(node->val);
// 将左子节点加入队列(无论是否为空,下一层都要处理)
que.push(node->left);
// 将右子节点加入队列(无论是否为空,下一层都要处理)
que.push(node->right);
} else {
// 当前节点为空,使用特殊值INT_MIN标记空节点
// 这是为了区分不同节点的值和空节点
levelValues.push_back(INT_MIN);
}
}
// 检查当前层的节点值数组是否对称
// 使用双指针从两端向中间比较
int left = 0, right = levelValues.size() - 1;
while (left < right) {
// 如果两端的值不相等,说明不是镜像对称
if (levelValues[left] != levelValues[right]) {
return false;
}
// 移动指针继续比较下一对
left++;
right--;
}
// 如果所有对称位置的节点值都相等,继续检查下一层
}
// 所有层都检查完毕且都对称,返回true
return true;
}
};
关键点详解:
-
空节点处理:
-
使用
INT_MIN标记空节点,确保能区分节点值为INT_MIN的情况 -
即使是空节点也要加入队列,确保层次结构正确
-
-
对称检查逻辑:
-
将每一层的节点值收集到数组中
-
使用双指针检查数组是否回文对称
-
每层独立检查,只要有一层不对称就返回false
-
-
算法步骤:
-
初始化队列,加入根节点
-
对于每一层:
-
获取当前层的所有节点值(包括空节点标记)
-
检查当前层是否对称
-
将下一层的节点加入队列
-
-
所有层都对称则返回true
-
-
注意事项:
-
这种方法将空节点也纳入检查,确保结构对称
-
可能存在的问题:如果树的节点值恰好等于
INT_MIN,可能会误判(可改用其他标记方法如INT_MAX或额外标记)
-
递归遍历
cpp
class Solution {
public:
// 比较两个子树是否镜像对称的递归函数
bool compare(TreeNode* left, TreeNode* right) {
// 情况1:左节点为空但右节点不为空,不对称
if (left == NULL && right != NULL) return false;
// 情况2:左节点不为空但右节点为空,不对称
else if (left != NULL && right == NULL) return false;
// 情况3:左右节点都为空,对称(递归终止条件之一)
else if (left == NULL && right == NULL) return true;
// 情况4:左右节点都不为空,但值不相等,不对称
else if (left->val != right->val) return false;
// 执行到这里说明:左右节点都不为空,且数值相同
// 需要继续递归检查下一层的子树
// 比较外层:左子树的左子节点 vs 右子树的右子节点
// 这是镜像对称的关键:外侧与外侧比较
bool outside = compare(left->left, right->right);
// 比较内层:左子树的右子节点 vs 右子树的左子节点
// 镜像对称的另一个关键:内侧与内侧比较
bool inside = compare(left->right, right->left);
// 只有外侧和内测都对称,当前这对节点才算对称
bool isSame = outside && inside;
return isSame;
}
// 判断整棵树是否镜像对称的主函数
bool isSymmetric(TreeNode* root) {
// 如果根节点为空,空树被认为是对称的
if (root == NULL) return true;
// 从根节点的左右子树开始比较
return compare(root->left, root->right);
}
};
举例:
1
/ \
2 2
\ \
3 3
第1步:调用 isSymmetric(root)
cpp
root = 节点1
return compare(节点1的左子树(2), 节点1的右子树(2))
第2步:调用 compare(节点2, 节点2)
cpp
参数: left = 节点2, right = 节点2
// 检查1:两个节点都不为空 → 通过
if (left == NULL && right != NULL) return false; // 不执行
else if (left != NULL && right == NULL) return false; // 不执行
else if (left == NULL && right == NULL) return true; // 不执行
// 检查2:值相等 → 通过
else if (left->val != right->val) return false; // 2 != 2? false,不执行
// 继续递归比较子树
第3步:递归比较子树
cpp
// 比较外层:左子树的左子节点 vs 右子树的右子节点
bool outside = compare(left->left, right->right);
// left->left = 空,right->right = 节点3
// compare(空, 节点3)
// 比较内层:左子树的右子节点 vs 右子树的左子节点
bool inside = compare(left->right, right->left);
// left->right = 节点3,right->left = 空
// compare(节点3, 空)
第4步:执行 compare(空, 节点3)
cpp
参数: left = 空, right = 节点3
// 检查第一个条件:
if (left == NULL && right != NULL) return false;
// left == NULL 成立,right != NULL 成立
// 所以返回 false
第5步:执行 compare(节点3, 空)
cpp
参数: left = 节点3, right = 空
// 检查第二个条件:
else if (left != NULL && right == NULL) return false;
// left != NULL 成立,right == NULL 成立
// 所以返回 false
第6步:回到 compare(节点2, 节点2)
cpp
bool outside = compare(空, 节点3) = false
bool inside = compare(节点3, 空) = false
bool isSame = outside && inside = false && false = false
return isSame = false
第7步:回到 isSymmetric
cpp
return compare(root->left, root->right) = false
最终结果:返回 false
cpp
isSymmetric(1)
|
v
compare(2, 2)
|
├── outside: compare(空, 3) → false
| 原因:左为空,右不为空 → 不对称
|
└── inside: compare(3, 空) → false
原因:左不为空,右为空 → 不对称
|
v
false && false = false