代码随想录算法训练营|二叉树总结

news2025/1/13 8:01:55

二叉树的定义:

struct TreeNode
{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode():val(0),left(nullptr),right(nullptr){}
	TreeNode(int val):val(val),left(nullptr),right(nullptr){}
	TreeNode(int val,TreeNode* left,TreeNode* right):val(val),left(left),right(right){}
}

其实二叉树就是一种类似链表结构(故打好链表基础十分重要!)。

各种遍历方法

在这里插入图片描述

前序遍历

前序遍历的顺序是中左右,用一个图来感受这个过程,前序遍历:5412678

递归法

class Solution {
public:
    vector<int> result;
    void preorder(TreeNode* node)
    {
        if(node==nullptr)return;
        result.push_back(node->val);
        preorder(node->left);
        preorder(node->right);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        result.clear();
        preorder(root);
        return result;
    }
};

迭代法

上面我们采用递归能做出来,递归的本质就是栈,故迭代法可用栈这种数据结构!

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> stk;
        //先判断是否需要push进去,首先需要push一个root进去,不然下面的while循环都进不去
        if(root==nullptr) return result;
        stk.push(root);
        while(!stk.empty())
        {
            TreeNode* node=stk.top();
            stk.pop();
            result.push_back(node->val);
            //一个注意点,应该先push右子树,因为栈的特点是先入后出
            if(node->right)stk.push(node->right);
            if(node->left)stk.push(node->left);
        }
        return result;
    }
};

中序遍历

递归法

中序遍历的顺序为左中右,参考上面的图,应该是1425768

class Solution {
public:
    vector<int> result;
    void inorder(TreeNode* node)
    {
        if(node==nullptr)return;
        preorder(node->left);
        result.push_back(node->val);
        preorder(node->right);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        result.clear();
        inorder(root);
        return result;
    }
};

迭代法

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*>stk;
        if(root==nullptr)return result;
        TreeNode* cur=root;
        while(!stk.empty()||cur!=nullptr)
        {
            if(cur)
            {
                stk.push(cur);
                cur=cur->left;
            }
            else
            {
                cur=stk.top();
                stk.pop();
                result.push_back(cur->val);
                cur=cur->right;
            }
        }
        return result;
    }
};

后序遍历

后序遍历:左右中,参考上面的图:1247865

递归法

class Solution {
public:
    vector<int> result;
    void postorder(TreeNode* node)
    {
        if(node==nullptr)return;
        preorder(node->left);
        preorder(node->right);
        result.push_back(node->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        result.clear();
        postorder(root);
        return result;
    }
};

迭代法

对比前序遍历顺序:中左右,后序遍历顺序为:左右中,如果我们将顺序变为:中右左,然后对于结果反转一下,是不是就是正确的呢?

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> stk;
        if(root==nullptr)return result;
        stk.push(root);
        while(!stk.empty())
        {
            TreeNode* node=stk.top();
            stk.pop();
            result.push_back(node->val);
            if(node->left)stk.push(node->left);
            if(node->right)stk.push(node->right);
        }
        reverse(result.begin(),result.end());
        return result;
    }
};

层序遍历

其实上文的前中后序遍历,在图论中就是DFS(深度优先搜索),而对应还有一种方法,那就是宽度优先搜索(BFS),其实对于BFS而言,用处还是蛮大的,很多需要遍历整个树的问题,用BFS做起来蛮方便的!当然要想实现BFS,也要借用一种数据结构,其用于存储每一层的元素!这种数据结构就是queue

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>>result;
        queue<TreeNode*> que;
        if(root==nullptr)return result;
        que.push(root);
        while(!que.empty())
        {
            int size=que.size();
            vector<int>vec;
            //在遍历上一层的同时,也将下一层的节点加入queue,这个过程
            while(size--)
            {
                TreeNode* node=que.front();
                que.pop();
                vec.push_back(node->val);
                if(node->left)que.push(node->left);
                if(node->right)que.push(node->right);
            }
            result.push_back(vec);
        }
        return result;
    }
};

二叉树遍历(带有回溯的)

236.二叉树的最近公共祖先

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr||root==p||root==q)return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left&&right)return root;
        else if(left==nullptr&&right)return right;
        else if(left&&right==nullptr)return left;
        else return nullptr;
    }
};

做完这道题,明白了公共祖先的问题,都是自顶向上的遍历(采用后序遍历)以及搜索整个树采用:

        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);

同样的一道题:255.二叉搜索树的最近公共祖先,但是这道题还有一个特点,每次要遍历左子树还是右子树的时候可以先进行判断,相当于进行剪枝操作了!

分解问题

将一个二叉树分解为左子树和右子树的问题!
其实要求遍历整个树的问题,很多时候都是分解问题,比较左子树和右子树的问题!
222.完全二叉树的节点个数
这是一道最基本的分解问题,求整个树的个数,分解为左子树加右子树再加根节点!(当然这里还有要遍历整个树要怎么写的问题!)

class Solution {
public:
    int traversal(TreeNode* node)
    {
        if(node==nullptr)return 0;
        int left=traversal(node->left);
        int right=traversal(node->right);
        //为什么这里是1+left+right呢?相当于左子树的个数加上右子树的个数再加上根节点(分解问题)
        return 1+left+right;
    }
    int countNodes(TreeNode* root) {
        return traversal(root);
    }
};

构造二叉树

关键点:在于不断确定中间节点,左子树以及右子树!
105.从前序与中序遍历序列构造二叉树

class Solution {
public:
    TreeNode* traversal(vector<int>& preorder,vector<int>& inorder)
    {
        if(preorder.size()==0)return nullptr;
        int rootvalue=preorder[0];
        TreeNode* root=new TreeNode(rootvalue);
        int index=0;
        for(;index<inorder.size();index++)
        {
            if(inorder[index]==rootvalue)break;
        }
        vector<int> leftinorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightinorder(inorder.begin()+index+1,inorder.end());
        vector<int> leftpreorder(preorder.begin()+1,preorder.begin()+1+leftinorder.size());
        vector<int> rightpreorder(preorder.begin()+1+leftinorder.size(),preorder.end());
        root->left=traversal(leftpreorder,leftinorder);
        root->right=traversal(rightpreorder,rightinorder);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0||inorder.size()==0) return nullptr;
        return traversal(preorder,inorder);
    }   
};

做过这道题,可以试试看
106.从中序与后序遍历序列构造二叉树

二叉搜索树

1.有序的问题!(联系中序遍历),求二叉搜索树中第k个最小值!一般做法:采用中序遍历,将二叉树变为有序数组,一定要采用中序遍历!
230.二叉搜索树中第K小的元素

class Solution {
public:
    vector<int> result;
    void inorder(TreeNode* root)
    {
        if(root==nullptr)return;
        inorder(root->left);
        result.push_back(root->val);
        inorder(root->right);
    }
    int kthSmallest(TreeNode* root, int k) {
        inorder(root);
        return result[k-1];
    }
};

98.验证二叉搜索树
这两道题都是将二叉搜索树的问题转换成数组问题来解决的!故对于二叉搜索树的很多问题一定要学会联系中序遍历!

路径问题

插入节点

701.二叉搜索树中的插入操作

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(root==nullptr)
        {
            TreeNode* node=new TreeNode(val);
            return node;
        }
        if(root->val<val)
        {
            root->right=insertIntoBST(root->right,val);
        }
        if(root->val>val)
        {
            root->left=insertIntoBST(root->left,val);
        }
        return root;
    }
};

删除节点

450.删除二叉搜索树的节点

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(root==nullptr)return nullptr;
        if(root->val==key)
        {
            if(root->left==nullptr)return root->right;
            else if(root->right==nullptr)return root->left;
            else if(root->left!=nullptr && root->right!=nullptr)
            {
                TreeNode* cur=root->right;
                while(cur->left!=nullptr)
                {
                    cur=cur->left;
                }
                cur->left=root->left;
                TreeNode* temp=root;
                root=root->right;
                delete temp;
                return root;
            }
        }
        if(root->val<key)root->right=deleteNode(root->right,key);
        if(root->val>key)root->left=deleteNode(root->left,key);
        return root;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1459381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网工内推 | 证券公司急招网工,base上海,年薪50W

01 广发证券 招聘岗位&#xff1a;网络工程师 任职要求&#xff1a; 1、懂基础建设网络&#xff0c;虚拟化&#xff0c;或者服务器中任意一个都可以&#xff08;需资深&#xff09;2、985/211本硕 3、年龄最好35以下 薪资待遇&#xff1a; 1、工作时间9:00-17:00 2、根据资历…

思腾合力邀您共赴第二届世界元宇宙大会

由中国仿真学会、中国指挥与控制学会和北京理工大学共同主办&#xff0c;上海市嘉定区安亭镇人民政府和中国仿真学会元宇宙专业委员会承办的第二届世界元宇宙大会大会以“虚实相生、产业赋能”为主题&#xff0c;聚焦元宇宙关键技术发展的共性问题&#xff0c;交流元宇宙技术产…

Window系统GPT-SoVITS配置安装

GPT-SoVITS配置安装 GPT-SoVITS配置Python下载以及安装源文件安装依赖 运行整理在安装配置环境时遇到的报错总结 GPT-SoVITS配置 作者链接 Python下载以及安装 版本这里根据教程的版本走即可&#xff0c;这里不会安装python或者不会配置环境的参考我之前的文章 Python 3.9,…

C# GTS四轴运动控制器实例(固高科技步进电机不带编码器)

注&#xff1a;由于电机不带编码器&#xff0c;无法做home和当前位置信息读取&#xff01; 功能&#xff1a; 三个轴的点位运动&#xff1a;前进后退&#xff0c;并分别显示每个轴的移动脉冲数(可以换算为距离)&#xff01; 开发环境&#xff1a;VS2017 硬件设备&#xff1a;固…

编程笔记 Golang基础 007 第一个程序:hello world 使用Goland

编程笔记 Golang基础 007 第一个程序&#xff1a;hello world 使用Goland 步骤1&#xff1a;启动GoLand并创建新项目步骤2&#xff1a;创建主包和主函数步骤3&#xff1a;运行程序小结 开始在Goland环境中编程go语言代码啦。 步骤1&#xff1a;启动GoLand并创建新项目 打开GoL…

[word] word中图片衬于文字下方无法显示 #媒体#微信

word中图片衬于文字下方无法显示 1、如图&#xff0c;图片“衬于文字下方”&#xff0c;文字下方的图象看不见 2、光标这位到图片上这段文字中&#xff0c;点击“格式”&#xff0d;“边框和底纹”&#xff0c;切换到“底纹”选项卡。可发现这两段文字底纹被设置成“白色”了 …

【数学建模入门】

数学建模入门 数学建模需要的学科知识怎么学习数学模型如何读好一篇优秀论文数学建模赛题常见类别数学建模常见问题数学建模组队和分工数学建模准备工作 数学建模需要的学科知识 怎么学习数学模型 &#x1f4a6;推荐阅读书籍&#xff1a; 《数学建模算法与应用》&#xff0c;…

OpenGL学习——17.模型

前情提要&#xff1a;本文代码源自Github上的学习文档“LearnOpenGL”&#xff0c;我仅在源码的基础上加上中文注释。本文章不以该学习文档做任何商业盈利活动&#xff0c;一切著作权归原作者所有&#xff0c;本文仅供学习交流&#xff0c;如有侵权&#xff0c;请联系我删除。L…

FlinkCDC详解

1、FlinkCDC是什么 1.1 CDC是什么 CDC是Chanage Data Capture&#xff08;数据变更捕获&#xff09;的简称。其核心原理就是监测并捕获数据库的变动&#xff08;例如增删改&#xff09;&#xff0c;将这些变更按照发生顺序捕获&#xff0c;将捕获到的数据&#xff0c;写入数据…

Vue | (二)Vue组件化编程 | 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;模块与组件、模块化与组件化&#x1f4da;非单文件组件&#x1f407;基本使用&#x1f407;关于组件的几个注意点&#x1f407;组件的嵌套 &#x1f4da;单文件组件&#x1f407;一个.vue 文件的组成&#x1f407;实例 学习链接&#xff1a;尚硅谷Vue2.0…

多线程、分布式运行用例

python多线程 threading模块 多线程实例 # -*- coding: utf-8 -*- # Time : 2024/2/7 15:50 # Author : 居里夫人吃橘子 # File : class01.py # Software: PyCharm import threading from time import sleepdef run(name):print(name 该起床了)sleep(2)print(name …

EXCEL使用VBA一键批量转换成PDF

EXCEL使用VBA一键批量转换成PDF 上图是给定转换路径 Sub 按钮1_Click() Dim a(1 To 1000) As String Dim a2 As String Dim myfile As String Dim wb As Workbook a2 Trim(Range("a2"))myfile Dir(a2 & "\" & "*.xls")k 0Do While m…

【LeetCode】树的BFS(层序遍历)精选6题

目录 1. N 叉树的层序遍历&#xff08;中等&#xff09; 2. 二叉树的锯齿形层序遍历&#xff08;中等&#xff09; 3. 二叉树的最大宽度&#xff08;中等&#xff09; 4. 在每个树行中找最大值&#xff08;中等&#xff09; 5. 找树左下角的值&#xff08;中等&#xff09…

2024.2.20

使用多进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半&#xff0c;子进程拷贝后一半&#xff0c;父进程回收子进程的资源 #include<myhead.h> int main(int argc, const char *argv[]) {char str[100]"";puts("please input str:");//从终端读…

手动实现new操作符

<script>//前置知识// 每一个函数在创建之初就会有一个prototype属性&#xff0c;这个属性指向函数的原型对象// function abc(){// }// abc.prototype--> {constructor: f}// 在JS中任意的对象都有内置的属性叫做[[prototype]]这是一个私有属性&#xff0c;这个私有属…

GEE数据集——美国两个主要石油和天然气(OG)产区内与石油和天然气(OG)相关的基础设施的位置

该数据集提供了美国两个主要石油和天然气&#xff08;O&G&#xff09;产区内与石油和天然气&#xff08;O&G&#xff09;相关的基础设施的位置&#xff1a;德克萨斯州西部和新墨西哥州南部二叠纪盆地的特拉华子盆地以及犹他州的乌因塔盆地。前言 – 人工智能教程 石油…

deep learning 代码笔记

1. pandas数据读取和预处理 # import pandas and load dataset import pandas as pd names [Sex, Length, Diameter, Height, Whole_weight, Shucked_weight, Viscera_weight, Shell_weight, Rings] data pd.read_csv(data_file, headerNone, namesnames) print(data) …

【前沿】头戴式光场显示技术研究进展

摘要&#xff1a;光场显示器旨在通过重建三维场景在不同方向发出的几何光线来渲染三维场景的视觉感知&#xff0c;从而为人的视觉系统提供自然舒适的视觉体验&#xff0c;解决传统平面立体三维显示器中的聚散调节冲突问题。近年来&#xff0c;多种光场显示方法被尝试应用到头戴…

沁恒CH32V30X学习笔记11---使用外部时钟模式2采集脉冲计数

使用外部时钟模式2采集脉冲计数 使用外部触发模式 2 能在外部时钟引脚输入的每一个上升沿或下降沿计数。将 ECE 位置位时,将使用外部时钟源模式 2。使用外部时钟源模式 2 时,ETRF 被选定为 CK_PSC。ETR 引脚经过可选的反相器(ETP),分频器(ETPS)后成为 ETRP,再经过滤波…

Stable Diffusion——stable diffusion基础原理详解与安装秋叶整合包进行出图测试

前言 在2022年&#xff0c;人工智能创作内容&#xff08;AIGC&#xff09;成为了AI领域的热门话题之一。在ChatGPT问世之前&#xff0c;AI绘画以其独特的创意和便捷的创作工具迅速走红&#xff0c;引起了广泛关注。随着一系列以Stable Diffusion、Midjourney、NovelAI等为代表…