156. 上下翻转二叉树
2. 题目叙述
给定一个二叉树,其中所有的右节点要么是具有兄弟节点(拥有相同父节点的左节点)的叶节点,要么为空,将此二叉树上下翻转并将它变成一棵树, 原来的右节点将转换成左叶节点。返回新的根。
3. 模式识别
本题可通过递归或者迭代的方式对二叉树进行节点关系的调整,从而实现上下翻转。核心在于明确每个节点在翻转后的新位置和新的连接关系。
4. 考点分析
- 二叉树的遍历和操作,需要理解如何在遍历过程中修改节点的连接关系。
- 递归和迭代思想的运用,能够通过递归调用或者迭代循环来完成树的转换。
5. 所有解法
- 递归解法:递归地处理左子树,将左子树上下翻转后,调整当前节点和其左右子节点的连接关系。
- 迭代解法:使用迭代的方式,借助栈或者直接模拟递归过程,逐步调整节点的连接关系。
6. 最优解法(递归解法)的C语言代码
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构
struct TreeNode {
int val; // 节点的值
struct TreeNode *left; // 左子节点指针
struct TreeNode *right; // 右子节点指针
};
// 递归函数,用于上下翻转二叉树
struct TreeNode* upsideDownBinaryTree(struct TreeNode* root) {
// 如果根节点为空或者根节点的左子节点为空,说明无需翻转,直接返回根节点
if (root == NULL || root->left == NULL) {
return root;
}
// 递归处理左子树,得到翻转后的新根节点
struct TreeNode* newRoot = upsideDownBinaryTree(root->left);
// 保存当前根节点的左子节点
struct TreeNode* leftChild = root->left;
// 保存当前根节点的右子节点
struct TreeNode* rightChild = root->right;
// 调整节点的连接关系
leftChild->left = rightChild; // 原左子节点的左子节点指向原右子节点
leftChild->right = root; // 原左子节点的右子节点指向原根节点
root->left = NULL; // 原根节点的左子节点置为空
root->right = NULL; // 原根节点的右子节点置为空
return newRoot; // 返回新的根节点
}
// 辅助函数,用于创建新的二叉树节点
struct TreeNode* createNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = NULL;
node->right = NULL;
return node;
}
// 辅助函数,用于释放二叉树的内存
void freeTree(struct TreeNode* root) {
if (root == NULL) {
return;
}
freeTree(root->left);
freeTree(root->right);
free(root);
}
int main() {
// 构建一个简单的二叉树
struct TreeNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
// 调用上下翻转函数
struct TreeNode* newRoot = upsideDownBinaryTree(root);
// 释放二叉树的内存
freeTree(newRoot);
return 0;
}
7. 复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的节点数。因为需要遍历二叉树的每个节点一次。
- 空间复杂度: O ( h ) O(h) O(h),其中 h h h 是二叉树的高度。递归调用栈的深度取决于二叉树的高度。在最坏情况下,二叉树退化为链表,空间复杂度为 O ( n ) O(n) O(n)。