当前位置: 首页 > article >正文

数据结构(六)—— 二叉树(3)

文章目录

  • 1 589 N 叉树的前序遍历
  • 2 226 翻转二叉树
    • 递归
    • 迭代
  • 3 101 对称二叉树
    • 递归
    • 迭代
  • 4 104 二叉树的最大深度
    • 层序遍历直接解决
    • 递归
  • 5 111 二叉树的最小深度
    • 层序遍历
    • 递归
  • 6 222 完全二叉树的节点个数
    • 递归
    • 遍历
  • 7 110 平衡二叉树
    • 递归


递归三部曲
1、确定递归函数的参数和返回值
2、确定终止条件
关键代码swap(root->left, root->right);
3、确定单层递归的逻辑

1 589 N 叉树的前序遍历

class Solution {
public:
    void trans(Node* root, vector<int>& res){
        if(root == NULL) return;
        res.push_back(root->val);
        for(int i = 0; i < root->children.size(); ++i){
            trans(root->children[i], res);
        }
    }

    vector<int> preorder(Node* root) {
        vector<int> res;
        trans(root, res);
        return res;
    }
};

2 226 翻转二叉树

递归

注意和上面前序遍历的差别

TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        swap(root->left, root->right);  // 中
        invertTree(root->left);         // 左
        invertTree(root->right);        // 右
        return root;
}

迭代

使用stack,深度优先遍历

TreeNode* invertTree(TreeNode* root) {
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while(!st.empty()){
            int size = st.size();
            for(int i = 0; i < size; ++i){
                TreeNode* temp = st.top();
                st.pop();
                swap(temp->left,temp->right);
                if(temp->left != NULL) st.push(temp->left);
                if(temp->right != NULL) st.push(temp->right);
            }
        }
        return root;
}

3 101 对称二叉树

递归

在这里插入图片描述
1、确定递归函数的参数和返回值
因为我们要比较的是根节点的两个子树是否是相互翻转,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。
返回是与否(bool)。
bool compare(NodeTree* left, NodeTree* right)
2、确定终止条件
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。

节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
左节点为空,右节点不为空,不对称,return false
左不为空,右为空,不对称 return false
左右都为空,对称,返回true

剩下的就是左右节点不为空
左右都不为空,比较节点数值,不相同就return false

if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false; // 注意这里没有使用else,因为还剩下左右节点都不为空,数值相同

3、确定单层递归的逻辑
此时才进入单层递归的逻辑,单层递归的逻辑就是处理左右节点都不为空,且数值相同的情况。
注意outside和inside是传的什么
比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。

bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

4、整合递归函数

bool compare(TreeNode* left, TreeNode* right) {
        // 首先排除空节点的情况
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;
        // 排除了空节点,再排除数值不相同的情况
        else if (left->val != right->val) return false;

        // 此时就是:左右节点都不为空,且数值相同的情况
        // 此时才做递归,做下一层的判断
        bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
        bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
        bool isSame = outside && inside;                    // 左子树:中、 右子树:中 (逻辑处理)
        return isSame;
}

总代码

bool isSymmetric(TreeNode* root) {
        if(root == NULL) return 0;
        return compare(root->left, root->right);
}

迭代

使用queue,广度优先遍历

注意,之前的层级遍历时,que中不能加入空节点,而此处需要加入空节点来判断是否对称

bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        queue<TreeNode*> que;
        que.push(root->left);   // 将左子树头结点加入队列
        que.push(root->right);  // 将右子树头结点加入队列
        
        while (!que.empty()) {  // 接下来就要判断这两个树是否相互翻转
            TreeNode* leftNode = que.front(); que.pop();
            TreeNode* rightNode = que.front(); que.pop();
            if (!leftNode && !rightNode) {  // 左节点为空、右节点为空,此时说明是对称的
                continue;
            }

            // 左右一个节点不为空,或者都不为空但数值不相同,返回false
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
                return false;
            }
            que.push(leftNode->left);   // 加入左节点左孩子
            que.push(rightNode->right); // 加入右节点右孩子
            que.push(leftNode->right);  // 加入左节点右孩子
            que.push(rightNode->left);  // 加入右节点左孩子
        }
        return true;
}

4 104 二叉树的最大深度

二叉树某一节点的深度:该节点到根节点的距离(根节点深度为1)
二叉树某一节点的高度:该节点到叶子节点的距离(叶子节点高度为1)

层序遍历直接解决

Depth++

递归

先用后序遍历(左右中)来计算树的高度。如果用后序遍历其实求的是二叉树的最大高度
1、确定递归函数的参数和返回值
参数就是传入树的根节点;返回就返回这棵树的深度,所以返回值为int类型。
int getdepth(treenode* node)

2、确定终止条件:如果为空节点的话,就返回0,表示高度为0。
if (node == NULL) return 0;

3、确定单层递归的逻辑
先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。

int leftdepth = getdepth(node->left);       // 左
int rightdepth = getdepth(node->right);     // 右
int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;

4、整合函数

int getdepth(treenode* node) {
        if (node == NULL) return 0;
        int leftdepth = getdepth(node->left);       // 左
        int rightdepth = getdepth(node->right);     // 右
        int depth = 1 + max(leftdepth, rightdepth); // 中
        return depth;
}

下面是前序遍历代码,前序遍历的逻辑才是二叉树的最大深度

class Solution {
public:
    int result;
    void getDepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // 中

        if (node->left == NULL && node->right == NULL) return ;

        if (node->left) { // 左
            depth++;    // 深度+1
            getDepth(node->left, depth);
            depth--;    // 回溯,深度-1
        }
        if (node->right) { // 右
            depth++;    // 深度+1
            getDepth(node->right, depth);
            depth--;    // 回溯,深度-1
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == NULL) return result;
        getDepth(root, 1);
        return result;
    }
};

5 111 二叉树的最小深度

题意:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

最近叶子节点:左右孩子都为空的节点才是叶子节点

层序遍历

int minDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if(root != nullptr) que.push(root);
        else return 0;
        int res = 1;
        while(!que.empty()){
            int size = que.size();
            for(int i = 0; i < size; ++i){
                TreeNode* temp = que.front();
                que.pop();
                if(temp->left != nullptr) que.push(temp->left);
                if(temp->right != nullptr) que.push(temp->right);
                
                if(temp->left == nullptr && temp->right == nullptr) return res;  // 变化的地方
            }
            res++;
        }
        return res;
}

递归

int minDepth(TreeNode* root) {
        if (!root) return 0;
        int res = INT_MAX;
        if (root->left) res = min(res, minDepth(root->left) + 1);
        if (root->right) res = min(res, minDepth(root->right) + 1);
        if (res == INT_MAX) res = 1;
        return res;
}

6 222 完全二叉树的节点个数

先按照普通二叉树写

递归

递归遍历的顺序依然是后序(左右中)。
1、确定递归函数的参数和返回值
参数就是传入树的根节点;返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
int getNodesNum(TreeNode* cur)

2、确定终止条件
如果为空节点的话,就返回0,表示节点数为0。
if (cur == NULL) return 0;

3、确定单层递归的逻辑
先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。

int leftNum = getNodesNum(cur->left);      // 左
int rightNum = getNodesNum(cur->right);    // 右
int treeNum = leftNum + rightNum + 1;      // 中
return treeNum;

遍历

层序遍历

7 110 平衡二叉树

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
既然要求比较高度,必然是要后序遍历

递归

该题与104二叉树最大深度用的递归思路一样,为后序遍历

1、明确递归函数的参数和返回值
参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。
int getHeight(TreeNode* node) // -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
2、明确终止条件:空节点终止
if (node == NULL) return 0;
3、明确单层递归的逻辑
如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。
分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。

int leftHeight = getHeight(node->left); // 左
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right); // 右
if (rightHeight == -1) return -1;

int result;
if (abs(leftHeight - rightHeight) > 1) {  // 中
    result = -1;
} else {
    result = 1 + max(leftHeight, rightHeight); // 以当前节点为根节点的树的最大高度
}

return result;

4、整合

int getHeight(TreeNode* node) {
    if (node == NULL) return 0;
    int leftHeight = getHeight(node->left);
    if (leftHeight == -1) return -1;
    int rightHeight = getHeight(node->right);
    if (rightHeight == -1) return -1;
    return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
}

http://www.kler.cn/news/16419.html

相关文章:

  • 【Linux多线程编程-自学记录】05.取消线程
  • Tomcat8和Tomcat9乱码问题
  • 浪潮之巅 OpenAI有可能是历史上第一个10万亿美元的公司
  • 一篇带你了解大厂都在用的DDD领域驱动设计
  • 【Canvas入门】从零开始在Canvas上绘制简单的动画
  • 高性能定时器介绍及代码逐行解析--时间堆
  • 走进小程序【十一】微信小程序【使用Echarts 和 腾讯地图】
  • R语言 | 数据框
  • MySQL数据库——MySQL修改视图(ALTER VIEW)
  • vim 常用操作(vimtutor阅读笔记)
  • 移动宽带安装说明一(刘欣)
  • 【第十一届泰迪杯B题】产品订单的数据分析与需求预测
  • Netty小白入门教程
  • tensorflow中Keras ---图像预处理----tf.keras.preprocessing.image.ImageDataGenerator 类
  • P1915 [NOI2010] 成长快乐
  • 三元操作 三元操作符 if-else / ? :
  • 进程控制下篇
  • [LeetCode]1033. 移动石子直到连续
  • 《基于光电容积法和机器学习的冠状动脉疾病患者出血风险预测》阅读笔记
  • 【Python2.x与Python3.x的区别】
  • 进程相关(创建-回收-exec-守护进程)
  • 【华为OD机试 2023最新 】任务总执行时长(C语言题解 100%)
  • BPMN2.0 任务-服务任务
  • LVS负载均衡集群--DR模式
  • Chapter1:控制系统数学模型(下)
  • LC-1033. 移动石子直到连续(分类讨论)
  • Ubuntu搜狗输入法安装指南
  • Redis入门指南:深入了解这款高性能缓存数据库
  • MySQL示例数据库(MySQL Sample Databases) 之 Employees 数据库
  • [AION]我眼中的《永恒之塔私服》