首页 > 其他分享 >代码随想录刷题记录(11)| 二叉树(二叉树理论基础,二叉树的递归遍历,迭代遍历,统一迭代,层序遍历)

代码随想录刷题记录(11)| 二叉树(二叉树理论基础,二叉树的递归遍历,迭代遍历,统一迭代,层序遍历)

时间:2024-06-20 13:59:19浏览次数:14  
标签:node 遍历 迭代 二叉树 root 节点 result

目录

(一)二叉树理论基础

1. 种类

2. 存储方式

3. 遍历方式

4. 二叉树的定义 

(二)二叉树的递归遍历

1. 思路

2. 递归遍历

(1)前序遍历

(2)中序遍历

(3)后序遍历

(三)二叉树的迭代遍历

1. 思路

2. 迭代遍历

 (1)前序

(2)中序

(3)后序

(四)二叉树的统一迭代

(五)二叉树的层序遍历

1. 思路

2. 层序遍历

3. 相关题目

 (1)二叉树的层序遍历Ⅱ

① 题目描述

② 解题过程 

 (2)二叉树的右视图

① 题目描述

② 解题过程 

 (3)二叉树的层的平均值

① 题目描述

② 解题过程 

 (4)N叉树的层序遍历

① 题目描述

② 解题过程 

 (5)在每个树行中找最大值

① 题目描述

② 解题过程 

 (6)填充每个节点的下一个右侧节点指针

① 题目描述

② 解题过程 

 (7)填充每个节点的下一个右侧节点指针Ⅱ

① 题目描述

② 解题过程 

 (8)二叉树的最大深度

① 题目描述

② 解题过程 

 (9)二叉树的最小深度

① 题目描述

② 解题过程 


(一)二叉树理论基础

1. 种类

  1. 满二叉树:只有度为0的结点和度为2的结点,并且度为0的结点在同一层上。
  2. 完全二叉树:除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。
  3. 二叉搜索树:节点有序。
  4. 平衡二叉搜索树(AVL 树):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。【C++中 map、set、multimap、multiset 的底层实现都是 AVL 树,所以 map、set 的增删操作时间时间复杂度是 logn】

 

2. 存储方式

        二叉树可以链式存储,也可以顺序存储,如果用数组存储,那么如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。

3. 遍历方式

二叉树主要有两种遍历方式:

  • 深度优先遍历:先往深走,遇到叶子节点再往回走。(常用栈)
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历:一层一层的去遍历。(常用队列)
    • 层序遍历

 

4. 二叉树的定义 

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

(二)二叉树的递归遍历

1. 思路

递归算法的三要素:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。

  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

2. 递归遍历

(1)前序遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)

难易程度:简单

标签:栈、树、深度优先搜索、二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    void DFS(TreeNode* root, vector<int>& result) {
        if(!root) return;
        result.push_back(root->val);
        DFS(root->left, result);
        DFS(root->right, result);
    }

public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        DFS(root, result);
        return result;
    }
};

 

(2)中序遍历

94. 二叉树的中序遍历 - 力扣(LeetCode) 

难易程度:简单

标签:栈、树、深度优先搜索、二叉树

class Solution {
private:
    void DFS(TreeNode* root, vector<int>& result) {
        if(!root) return;
        DFS(root->left, result);
        result.push_back(root->val);
        DFS(root->right, result);
    }

public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        DFS(root, result);
        return result;
    }
};

 

(3)后序遍历

145. 二叉树的后序遍历 - 力扣(LeetCode)

难易程度:简单

标签:栈、树、深度优先搜索、二叉树

class Solution {
private:
    void DFS(TreeNode* root, vector<int>& result) {
        if(!root) return;
        DFS(root->left, result);
        DFS(root->right, result);
        result.push_back(root->val);
    }

public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        DFS(root, result);
        return result;
    }
};

 

(三)二叉树的迭代遍历

1. 思路

        递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。那么用栈也可以是实现二叉树的前后中序遍历。

2. 迭代遍历

 (1)前序

        前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> preStack;
        if(!root) return result;
        preStack.push(root);
        while(!preStack.empty()) {
            TreeNode* node = preStack.top();
            preStack.pop();
            result.push_back(node->val);
            if(node->right) preStack.push(node->right);
            if(node->left)  preStack.push(node->left);
        }
        return result;
    }
};

 

(2)中序

        中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进 result 数组中),这就造成了处理顺序和访问顺序是不一致的。那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

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

 

(3)后序

        先序遍历是中左右,后续遍历是左右中,只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。

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

 

(四)二叉树的统一迭代

        将访问的节点放入栈中,把要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。

(五)二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣(LeetCode)

1. 思路

        层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。需要借用一个辅助队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。而这种层序遍历方式就是图论中的广度优先遍历。

2. 层序遍历

难易程度:中等

标签:树、广度优先搜索、二叉树

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        queue<TreeNode*> que;
        if(root) {
            que.push(root);
        }
        while(!que.empty()) {
            int size = que.size();
            vector<int> temp;
            for(int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                temp.push_back(node->val);
                if(node->left)  que.push(node->left);
                if(node->right) que.push(node->right);
            }
            result.push_back(temp);
        }
        return result;
    }
};

 

3. 相关题目

 (1)二叉树的层序遍历Ⅱ

107. 二叉树的层序遍历 II - 力扣(LeetCode)

① 题目描述

        给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

② 解题过程 

 难易程度:中等

标签:树、广度优先搜索、二叉树

        层序遍历结果一层一层倒着输出。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        queue<TreeNode*> que;
        if(root)    que.push(root);
        while(!que.empty()) {
            int size = que.size();
            vector<int> temp;
            for(int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                temp.push_back(node->val);
                if(node->left)  que.push(node->left);
                if(node->right) que.push(node->right);
            }
            result.push_back(temp);
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

 

 (2)二叉树的右视图

199. 二叉树的右视图 - 力扣(LeetCode)

① 题目描述

        给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

② 解题过程 

 难易程度:中等

标签:树、深度优先搜索、广度优先搜索、二叉树

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> result;
        queue<TreeNode*> que;
        if(root) {
            que.push(root);
        }
        while(!que.empty()) {
            int size = que.size();
            for(int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                // 只有当前层最右侧的放到result
                if(i == size - 1) {
                    result.push_back(node->val);
                }
                if(node->left)  que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return result;
    }
};

 

 (3)二叉树的层的平均值

637. 二叉树的层平均值 - 力扣(LeetCode)

① 题目描述

        给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

 

② 解题过程 

 难易程度:简单

标签:树、深度优先搜索、广度优先搜索、二叉树

        (其中不用那个判断,直接在 for 循环结束后 /size 就可以了) 

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> result;
        queue<TreeNode*> que;
        if(root)    que.push(root);
        while(!que.empty()) {
            int size = que.size();
            double count = 0.0;
            for(int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                count += node->val;
                if(node->left)  que.push(node->left);
                if(node->right) que.push(node->right);
                // 这层的最后一个结点,将这层节点的和除以节点数量
                if(i == size - 1)   result.push_back(count / size);
            }
        }
        return result;
    }
};

 

 (4)N叉树的层序遍历

429. N 叉树的层序遍历 - 力扣(LeetCode)

① 题目描述

        给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。

        树的序列化输入是用层序遍历,每组子节点都由 null 值分隔。

 

② 解题过程 

 难易程度:中等

标签:树、广度优先搜索

 

 (5)在每个树行中找最大值

515. 在每个树行中找最大值 - 力扣(LeetCode)

① 题目描述

        给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

 

② 解题过程 

 难易程度:中等

标签:树、深度优先搜索、广度优先搜索、二叉树

 

 (6)填充每个节点的下一个右侧节点指针

116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)

① 题目描述

        给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
    int val;
    Node *left;
    Node *right;
    Node *next;
}

        填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

        初始状态下,所有 next 指针都被设置为 NULL

 

② 解题过程 

 难易程度:中等

标签:树、深度优先搜索、广度优先搜索、链表、二叉树

 

 (7)填充每个节点的下一个右侧节点指针Ⅱ

117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)

① 题目描述

        给定一个二叉树:

struct Node {
    int val;
    Node *left;
    Node *right;
    Node *next;
}

        填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

        初始状态下,所有 next 指针都被设置为 NULL

 

② 解题过程 

 难易程度:中等

标签:树、深度优先搜索、广度优先搜索、链表、二叉树

 

 (8)二叉树的最大深度

104. 二叉树的最大深度 - 力扣(LeetCode)

① 题目描述

        给定一个二叉树 root ,返回其最大深度。

        二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

 

② 解题过程 

 难易程度:简单

标签:树、深度优先搜索、广度优先搜索、二叉树

 

 (9)二叉树的最小深度

111. 二叉树的最小深度 - 力扣(LeetCode)

① 题目描述

        给定一个二叉树,找出其最小深度。

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

        说明:叶子节点是指没有子节点的节点。

 

② 解题过程 

 难易程度:简单

标签:树、深度优先搜索、广度优先搜索、二叉树

标签:node,遍历,迭代,二叉树,root,节点,result
From: https://blog.csdn.net/weixin_44839832/article/details/139801967

相关文章

  • 【YOLOv10改进[注意力]】使用迭代注意力特征融合(iterative attentional feature fusio
    本文将进行使用迭代注意力特征融合(iterativeattentionalfeaturefusion,iAFF)改进c2f ,助力YOLOv10目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。改进前和改进后的参数对比: 目录一AttentionalFeatureFusion(2020)二使用......
  • 设计模式-迭代器模式
    迭代器模式迭代器模式,又称为游标模式,它提供一种顺序访问集合/容器对象元素的方法,而又无需暴漏集合内部表示。迭代器模式可以为不同的容器提供一致的遍历行为,而不用关心容器内容元素组成结构,属于行为型模式。角色:抽象迭代器Iterator:负责定义访问和遍历元素的接口具体迭代器Con......
  • Python 迭代器与生成器
    迭代器迭代器(Iterator)是一个可以记住遍历的位置的对象,该对象包含值的可计数数字,在Python当中:迭代器是实现迭代器协议的对象,它包含方法__iter__()和__next__()__iter__()方法作用:返回迭代器对象本身__next__()方法作用:返回迭代器的下一个元素,如果没有元素了则就会触发Sto......
  • Python 遍历文件每一行判断是否只有一个换行符详解
    前言在文件处理过程中,判断文件每一行是否只有一个换行符是一个常见需求。作为测试工程师,我们经常需要对文件的格式进行验证,确保数据的完整性和规范性。本文将详细介绍如何使用Python遍历文件的每一行,并判断每一行是否只有一个换行符。需求分析我们需要编写一个Python程序,......
  • 考研系列-数据结构第五章:树与二叉树(上)
    目录写在前面:一、树的基本知识点1.树的基本概念2.树的常见术语(1)结点之间的关系描述(2)结点、树的属性描述(3)有序树和无序树对比(4)树和森林对比(5)总结3.树常考性质(1)结点数=总度数+1(2)度为m的树VSm叉树(3)树的层数(高度)和结点个数(4)求树最多/最少结点......
  • JQuery高级29_动画&遍历1
    一、动画三种方式显示和隐藏元素1、默认显示和隐藏方式 1.show([speed,[easing],[fn]]) 参数:   1.speed:动画的速度。三个预定义的值("slow","normal","fast")或表示动画时长的毫秒数值(如:1000)   2.easing:......
  • 103. 二叉树的锯齿形层序遍历
    /***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint*Left*TreeNode*Right*TreeNode*}*/funczigzagLevelOrder(root*TreeNode)[][]int{//层序遍历改下ifroot==nil{returnnil}que......
  • golang中用chan实现迭代器
    实现代码如下:packagemainimport( "log" "time")/* 两种迭代器的实现*///采用index的方式实现(非线程安全)typeListStructstruct{ indexint data[]int}func(sl*ListStruct)Next()int{ d:=sl.data[sl.index] sl.index+=1 returnd}func(......
  • 从零开始学数据结构系列之第三章《先序线索二叉树查找及总代码》
    文章目录查找下一个节点总代码往期回顾查找下一个节点​  我们为啥没有像中序二叉树一样有第一个节点,因为我们一开始最大就是我们的根节点,所以无需遍历去寻找我们的第一个节点,我们的T就是我们的第一个节点​我们回过来看中序线索二叉树的节点应该是怎么写的/*......
  • 二叉树的基础讲解
    二叉树在遍历,查找,增删的效率上面都很高,是数据结构中很重要的,下面我们来基础的认识一下。(高级的本人还没学,下面的代码用伪代码或C语言写的)我会从树,树的一些专有名词,树的遍历,二叉树,二叉树的遍历以及后面升级的树进行一部分的介绍。树首先我们从最开始的树来进行讲解,我们知道......