首页 > 编程语言 >代码随想录算法训练营第十一天| 144. 二叉树的前序遍历 , 94. 二叉树的中序遍历, 145.二叉树的后序遍历

代码随想录算法训练营第十一天| 144. 二叉树的前序遍历 , 94. 二叉树的中序遍历, 145.二叉树的后序遍历

时间:2024-07-22 15:26:19浏览次数:14  
标签:result 遍历 TreeNode val 随想录 right 二叉树 root left

今天主要学习了二叉树的基本概念,以及多种遍历方法。包含分别使用迭代思想和递归思想的前序遍历,中序遍历,后序遍历以及层次遍历。

二叉树的基础知识

二叉树

二叉树的种类可以分为满二叉树和完全二叉树。满二叉树指的是一个二叉树仅包含度为0和度为2的结点,并且度为0的节点在同一层。如图所示:

   1   
  / \
 2   3
/ \ / \
4 5 6 7

完全二叉树是指除最底层节点可能没填满,其余每层节点数都达到最大值,并且最下层的结点集中在该层最左边的若干位置。下面是一个完全二叉树的辨析图

二叉搜索树

二叉搜索树是有序树。左子树所有节点的值均小于根节点的值,右子树所有节点的值均大于根节点的值。如下图所示

平衡二叉搜索树是一种特殊的二叉搜索树,又被称为AVL树。性质如下:他是一棵空树或左右子树的高度差绝对值不超过1.

在底层容器中,set,multimap,multiset的底层实现都是平衡二叉搜索树,所以增删操作为logn。

基本实现

一般存储二叉树时,会多使用到链表进行存储。而对于每个结点的属性,我们一般按照如下方式进行定义。需要定义节点的值以及指向左右子节点的指针。
 

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

遍历方式总结

二叉树的前序遍历

题目链接: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 {
public:
    void travel(TreeNode* node,vector<int> &vec)
    {
        if(node==NULL) return;
        vec.push_back(node->val);
        travel(node->left,vec);
        travel(node->right,vec);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        travel(root,result);
        return result;
    }
};

接着是迭代遍历方法,需要借助栈这一数据结构进行实现。依旧是先访问根节点,然后依次将右结点、左节点进行入栈操作。需要注意的是,这里是右结点先入栈,因为我们的输出顺序是中左右,左节点后入栈才能先出栈。这里的入栈顺序是需要推敲一下的。代码实现如下:

/**
 * 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 {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> ss;
        if(root==NULL) return result;
        ss.push(root);
        while(!ss.empty())
        {
            TreeNode* node=ss.top();
            ss.pop();
           result.push_back(node->val);
           if(node->right) ss.push(node->right);
           if(node->left)  ss.push(node->left);
        }
        return result;
    }
};

二叉树的中序遍历

题目链接:94. 二叉树的中序遍历 - 力扣(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 {
public:
    void travel(TreeNode* root,vector<int> &vec)
    {
        if(root==NULL) return;
        travel(root->left,vec);
        vec.push_back(root->val);
        travel(root->right,vec);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        travel(root,result);
        return result;
    }
};

接着是迭代遍历方法。中序遍历的迭代遍历方法有些特殊,他的思想是先一直遍历左节点并入栈,直到左节点为空,此时将栈顶元素出栈并放入输出数组中,在遍历栈顶元素的右子树。其本质思想就是深度优先搜索,遇到空节点就进行回溯。还是有点难理解的,需要多写两遍。实现代码如下:
 

/**
 * 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 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode* cur=root;
        while(cur!=NULL||!st.empty())
        {
            if(cur!=NULL)
            {
                st.push(cur);
                cur=cur->left;
            }
            else
            {
               cur=st.top();
                st.pop();
                result.push_back(cur->val);
                cur=cur->right;
            }
        }
        return result;
    }
};

二叉树的后序遍历

题目链接:145. 二叉树的后序遍历 - 力扣(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 {
public:
    void travel(TreeNode* root,vector<int> &vec)
    {
        if(root==NULL) return;
        travel(root->left,vec);
        travel(root->right,vec);
        vec.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        travel(root,result);
        return result;
    }
};

对于迭代遍历,后序遍历与前序遍历思想是一致的。后序输出顺序是左右中,那么我们只需要使用栈输出一个中右左,然后把输出数字进行翻转即可。由于是中右左,所以先入栈左节点在入栈右节点,输出时右结点就可以先行出栈,代码实现如下:
 

/**
 * 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 {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if(root!=nullptr) st.push(root);
        while(!st.empty())
        {
            TreeNode* node=st.top();
            st.pop();
            result.push_back(node->val);
            if(node->left) st.push(node->left);
            if(node->right) st.push(node->right);
        }
        reverse(result.begin(),result.end());
        return result;
    }
};

二叉树的层次遍历

题目链接:102. 二叉树的层序遍历 - 力扣(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 {
public:
void order(TreeNode* root,vector<vector<int>> &result,int depth)
{
    if(root==NULL) return;
    if(result.size()==depth) result.push_back(vector<int>());
    result[depth].push_back(root->val);
    order(root->left,result,depth+1);
    order(root->right,result,depth+1);
}
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        order(root,result,0);
        return result;
    }
};

接着是迭代遍历方法,需要借助队列这一数据结构。我们需要统计每一层的节点个数,按照个数进行出队列,并将左右节点进行入队列的操作。这样可以保证每一层的结点在不同的数组中,当一层的节点遍历完成,将该一维数组添加到二维数组中作为一层的输出结果。当队列为空说明遍历完成。代码实现如下:

/**
 * 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 {
public:
void order(TreeNode* root,vector<vector<int>> &result,int depth)
{
    if(root==NULL) return;
    if(result.size()==depth) result.push_back(vector<int>());
    result[depth].push_back(root->val);
    order(root->left,result,depth+1);
    order(root->right,result,depth+1);
}
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        order(root,result,0);
        return result;
    }
};

总结

今天内容比较多。首先学习了二叉树的基本知识,包括满二叉树、完全二叉树、二叉搜索树、平衡二叉搜索树,以及二叉树的存储方式和遍历方式。对于前序、中序、后序、层次遍历、四种遍历方式,每一种都有递归处理和迭代处理两种写法。都需要熟练的联系和掌握。

标签:result,遍历,TreeNode,val,随想录,right,二叉树,root,left
From: https://blog.csdn.net/m0_62154842/article/details/140610045

相关文章

  • 代码随想录算法训练营第一天leetcode704二分查找27移除元素
    leetcode704,这是leetcode提交四次后通过的结果:classSolution{  publicintsearch(int[]nums,inttarget){    if(nums.length==1&&nums[0]==target)      return 0;    if(nums.length==2)      if(nums[0]==target)......
  • Day 20 二叉树part07
    235.二叉搜索树的最近公共祖先总体上思想与236.二叉树的最近公共祖先思路是一致的,都是去搜索p,q的位置。这个大框架是最难理解的部分,具体可以再去看看236的题解。这道题在其基础上利用了搜索树的性质,当根节点的val大于pq两者时,就去左子树找结果即可;反之则去右子树中查找。当p,q一......
  • 代码随想录day6 | 242 有效字母异位词 349 两个数组交际 202 快乐数 1 两数之和
    hash表遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法242判断字母异位词关于字符串的遍历问题//什么情况下遍历的是rune[]int36类型,什么情况下遍历的是char字节类型?s:="Hello,世界"fori,r:=ranges{ fmt.Printf("Index:%d,Rune:%c,......
  • 代码随想录算法训练营第36天 | 动态规划基础2:62.不同路径、63.不同路径 II
    62.不同路径https://leetcode.cn/problems/unique-paths/submissions/548656029/代码随想录https://programmercarl.com/0062.不同路径.html63.不同路径IIhttps://leetcode.cn/problems/unique-paths-ii/description/代码随想录https://programmercarl.com/0063.不同路径......
  • OpenCV 遍历Mat,像素操作,使用TrackBar 调整图像的亮度和对比度 C++实现
    文章目录1.使用C++遍历Mat,完成颜色反转1.1常规遍历方式1.2迭代器遍历方式1.3指针访问方式遍历(最快)1.4不同遍历方式的时间对比2.图像像素操作,提高图像的亮度3.TrackBar进度条操作3.1使用TrackBar调整图像的亮度3.2使用TrackBar调整图像的对比度1.使用C++遍历M......
  • 一入循环深似海,代码随想录螺旋矩阵二刷
    代码随想录螺旋矩阵二刷leetcode59来看下螺旋矩阵。螺旋矩阵这道题确实很容易写着写着就绕进去了。首先读下题。给出正整数n,生成n*n的矩阵。我们来看其中一个用例,完成一个圈是需要四个循环去填充。但是四条边填充的时候要始终保持一样的规则,比如左闭右开的规则。那么转几圈呢......
  • 代码随想录训练营 Day4打卡 链表part02 24. 两两交换链表中的节点 19.删除链表的倒数
    代码随想录训练营Day4打卡链表part02一、力扣24.两两交换链表中的节点给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。示例1:输入:head=[1,2,3,4]输出:[2,1,4,3]算法思路:引入虚......
  • 代码随想录算法训练营第16天 | 二叉树更加进阶
    2024年7月18日用层序遍历巧解题513.找树左下角的值层序遍历的板子一定要熟背。classSolution{publicintfindBottomLeftValue(TreeNoderoot){List<List<Integer>>res=newArrayList<>();//用根左右遍历,每次记录高度intheight=0;......
  • 代码随想录算法训练营第15天 | 二叉树进阶
    2024年7月17日平衡二叉树/***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*TreeNode(intval){this.val=val;}*TreeNode(intval,TreeNodeleft......
  • JS 对象的遍历
    ​定义一个对象,对象的键包含所有数据类型constSymbolKey=Symbol('a')constdict={[66]:66,"string":'string',[true]:true,[undefined]:undefined,[null]:null,[BigInt(123)]:BigInt(123),[function(){console.log("h......