首页 > 其他分享 >144. 二叉树的遍历「前序、中序、后序」 Golang实现

144. 二叉树的遍历「前序、中序、后序」 Golang实现

时间:2024-11-21 17:07:43浏览次数:1  
标签:144 遍历 nil res 前序 节点 二叉树 root stack

题目描述:

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

思路分析:

递归法:

前序遍历的顺序是中左右的顺序。那么每个子树都是这个顺序,所以可以使用递归进行遍历。递归遍历有3部曲
	1.确定递归函数的参数和返回值。
		因为返回值要求保存在一个数组中,所以递归函数的参数应该包括树的根节点和结果数组
		` func preOrder(root *TreeNode,res *[]int) `
	2.确定递归函数的终止条件
		对于前序遍历来说,当某个根节点没有孩子节点的时候终止遍历。
		```
		if root==nil {
                	return
				 } ```
	3.确定单层递归的逻辑
		按照顺序进行遍历即可。
	   *res = append(*res, root.Val)
			preOrder(root.Left,res)
			 preOrder(root.Right,res)

最终的代码为:

点击查看代码
func preorderTraversal(root *TreeNode) []int {
//    递归函数3步骤:
//    1.确定递归函数的参数  2.确定递归函数的停止条件  3.确定单层递归的调用逻辑
   var res []int
   preOrder(root,&res)
   return res
}

func preOrder(root *TreeNode,res *[]int){
   if root==nil {
       return
   }
   *res = append(*res, root.Val)
   preOrder(root.Left,res)
   preOrder(root.Right,res)
}

中序遍历:

点击查看代码
func inorderTraversal(root *TreeNode) []int {
   var res []int
   if root==nil{
       return res
   }
   getOrder(root,&res)
   return res
}

func getOrder(root *TreeNode, res *[]int)  {
   if root!=nil {
       getOrder(root.Left,res)
       *res = append(*res, root.Val)
       getOrder(root.Right,res)
   }
}

后序遍历:

点击查看代码
func postorderTraversal(root *TreeNode) []int {
   var res []int
   postOrder(root,&res)
   return res
}

func postOrder(root *TreeNode,res *[]int)  {
   if root==nil{
       return
   }
   postOrder(root.Left,res)
   postOrder(root.Right,res)
   *res = append(*res, root.Val)
}

非递归版本

上方是三种遍历的递归方式,一定要明确递归的3个步骤。但是递归一般复杂度高,很难解决数据量大的数据。在计算机中递归就是用栈实现的,所以我们可以用栈来实现递归函数的非递归版本。但是三种遍历方式的写法会有区别。

三种遍历的非递归其实都是从根节点开始按照根左右的方式入栈,区别就在于什么时候应该出栈

前序遍历

前序遍历的顺序是根左右,由于是栈来实现,所有实际的入栈顺序是根右左,当访问到根的时候将根节点入栈--记录其值,然后将根节点出栈,按照根节点的右左孩子的顺序入栈,再根据栈顶元素作为根节点进行处理。函数结束条件则是栈的长度大于0.

点击查看代码
func preorderTraversal(root *TreeNode) []int{
    var res []int
    if root==nil{
        return res
    }
    var stack []*TreeNode
    stack = append(stack, root)
    for len(stack)>0 {
        node:=stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        if node!=nil {
            res = append(res, node.Val)
        }
        if node.Right != nil {
            stack = append(stack, node.Right)
        }
        if node.Left!=nil {
            stack = append(stack, node.Left)
        }
    }
    return res
}

中序遍历

中序的遍历顺序是左中右
入栈顺序:从根节点开始,首先将当前节点的左子树一路压入栈中,直到当前节点没有左子树为止。
出栈条件:当栈顶节点没有左子树时,出栈该节点并访问它,然后继续对其右子树进行遍历。

函数结束条件是 root!=nil || len(stack)>0 这是因为当遍历完左子树之后,回溯到整个树的root的时候,栈已经空了,但是右子树还没有入栈,所以还需要判断root是否为空。

点击查看代码
func inorderTraversal(root *TreeNode) []int{
    if root==nil {
        return []int{}
    }
    res,stack:=[]int{},[]*TreeNode{}
    for root!=nil || len(stack)>0 {
    //    先遍历左子树
        for root!=nil {
            stack = append(stack, root)
            root = root.Left
        }
    //    处理当前节点,最左下方的节点
        root = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        res = append(res, root.Val)
    //    遍历右子树
        root = root.Right
    }
    return res
}

后序遍历

后序遍历的顺序是:左-右-根。
入栈顺序: 从根节点开始,首先将当前节点压入栈中,然后按照“左右”的顺序将节点的左孩子和右孩子压入栈中。
出栈条件: 每次出栈栈顶元素后,仅在左右子树都已访问完成的情况下才访问根节点。为了保证这一点,通常需要借助一个额外的标记。所以我们通过pre指针来判断左右孩子是否已经访问过,只有他们都被访问过才能访问根节点。
因为入栈顺序,所以栈顶元素必然是叶子节点,通过prev记录上一次访问的节点,如果当前节点是叶子节点,直接记录;若不是叶子节点,如果prev是当前节点的任一孩子,说明孩子节点访问完毕「2种情况,2个孩子和只有一个孩子,模拟一下便知」,则可以访问根节点了。

点击查看代码
func postorderTraversal(root *TreeNode) []int{
    if root==nil{
        return []int{}
    }
    res,stack := []int{},[]*TreeNode{}
    var prev *TreeNode

    stack = append(stack, root)
    for len(stack)>0{
        current:=stack[len(stack)-1]
    if(current.Left== nil && current.Right ==nil) || (prev!=nil && (prev == current.Left || prev==current.Right)){
        res = append(res, current.Val)
        stack = stack[:len(stack)-1]
        prev = current
    }else{
        if current.Right!=nil {
            stack = append(stack, current.Right)
        }
        if current.Left != nil {
            stack = append(stack, current.Left)
        }
    }
    }
    return res
}

标签:144,遍历,nil,res,前序,节点,二叉树,root,stack
From: https://www.cnblogs.com/CharlseGo/p/18546735

相关文章

  • 代码随想录——二叉树19.最大二叉树
    递归最容易想到,采用先序遍历。1.遍历数组,找出当前区间的最大值;2.使用该最大值作为根节点;3.对数组的左半部分和右半部分递归调用构建最大二叉树。这种方式是标准的分治法,每次递归都需要遍历当前区间,找到最大值。因此,时间复杂度是O(n^2),因为每一层递归都会遍历一遍数组,且递......
  • 数据结构在二叉树中用子问题思路来解决问题
    二叉树Oj题获取二叉树的节点数获取二叉树的终端节点个数获取k层节点的个数获取二叉树的高度检测为value的元素是否存在判断两颗树是否相同判断是否是另一棵的子树反转二叉树判断一颗二叉树是否是平衡二叉树时间复杂度O(n*n)复杂度O(N)二叉树的遍历判断是否是对称的二叉......
  • 数据结构/第五章 树与二叉树/数据结构习题/树与二叉树的习题/考研/期末复习
    一、选择题1.一棵树中,所有结点的度数之和为n,则该树共有(    )个结点。A.n-1   B.n   C.n+1   D.无法确定2.高度为4的3叉树至多有(    )个结点。A.6   B.27   C.40   D.803.度为m的树中第6层至多有(    ......
  • 力扣 LeetCode 111. 二叉树的最小深度(Day7:二叉树)
     解题思路:用后序遍历题目要求的最小深度为根节点到叶子节点的最小深度,注意是到根节点,所以如图所示假设(没有9这个节点)是需要返回3的,而不是1(根节点左子树为空的情况),于是需要加两层判断其余部分可参考求最大深度的思路,有一定相似之处classSolution{publicintminDe......
  • 【PTA】求二叉树的右视图
    1.题目描述将二叉树的“右视图”定义为从二叉树右侧能看到的所有结点从上到下排列形成的序列。如下图所示的二叉树,其右视图就是{A,C,I,H}。 二叉树中的数据元素为单个字符,且各不相同,取值范围为A~Z或a~z之间的字符,二叉树不为空。在第3次上机“二叉树的建立和遍历”......
  • 帝国CMS存在SQL注入漏洞(CNVD-2024-4321448、CVE-2023-50073)
    帝国CMS(EmpireCMS )是一款非常出名的网站管理系统,用户也非常多。 国家信息安全漏洞共享平台于2024-11-06公布其存在SQL注入漏洞。漏洞编号:CVE-2024-44725、CNVD-2024-43215影响产品:帝国CMSV7.5漏洞级别:高公布时间:2024-11-06漏洞描述:帝国CMS v7.5版本存在SQL注入漏洞,该漏......
  • 数据结构——小小二叉树第一幕(树的认知以及顺序结构二叉树(堆)的实现)超详细!!!!
    文章目录前言一、树1.1树的概念与结构1.2数相关术语1.3树的表示1.4树形结构的实际运用场景二、二叉树2.1概念与结构2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树2.3二叉树存储结构2.3.1顺序结构2.3.2链式结构三、实现顺序结构二叉树3.1堆的概念与结构3.......
  • 102. 二叉树的层序遍历【 力扣(LeetCode) 】
    文章目录零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码零、原题链接102.二叉树的层序遍历一、题目描述给你二叉树的根节点root,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。二、测试用例示例1:输入:root=[3,9,20,null,nul......
  • java+SSM+MySQL非遗传承背景下甘肃人文宣传网站051441-计算机毕设 原创(赠源码)
    摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对非遗传承背景下甘肃人文宣传网站等问题,对非遗传承背景下甘肃人文宣传网站进行研究分析,然后开......
  • 根据二叉树的前序和中序构建树,并按层次输出(C++)vector存树
    L2-006树的遍历#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;#defineendl'\n'intpo[35];intino[35];vector<int>ans[50];intdfs(intl1,intr1,intl2,intr2){ for(inti=l2;i<=r2;i++){ if......