当前位置:首页 > 后端开发 > 正文内容

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

邻居的猫1个月前 (12-09)后端开发735

标题描绘:

给你二叉树的根节点 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
}

扫描二维码推送至手机访问。

版权声明:本文由51Blog发布,如需转载请注明出处。

本文链接:https://www.51blog.vip/?id=176

分享给朋友:

“144. 二叉树的遍历「前序、中序、后序」 Golang完成” 的相关文章

ASP.NET Core 标识(Identity)结构系列(三):在 ASP.NET Core Web API 项目中运用标识(Identity)结构进行身份验证

ASP.NET Core 标识(Identity)结构系列(三):在 ASP.NET Core Web API 项目中运用标识(Identity)结构进行身份验证

前语:JWT完结登录的流程 客户端向服务器端发送用户名、暗码等恳求登录。 服务器端校验用户名、暗码,假如校验成功,则从数据库中取出这个用户的ID、人物等用户相关信息。 服务器端选用只需服务器端才知道的密钥来对用户信息的 JSON 字符串进行签名,构成签名数据。 服务器端把用户信息的 JSON 字符...

怎么打开php文件,全面指南

在Windows系统中,你可以通过以下步骤打开PHP文件:1. 安装PHP环境:确保你的计算机上安装了PHP环境。你可以从PHP官方网站下载并安装PHP。2. 安装文本编辑器:安装一个文本编辑器,如Notepad 、Sublime Text或Visual Studio Code等。这些编辑器支持多...

go 热更新,使用Nacos实现配置文件实时更新

go 热更新,使用Nacos实现配置文件实时更新

1. 使用轻量级容器:将Go应用程序部署在轻量级的容器中,如Docker。通过替换容器中的镜像,可以实现快速的应用更新,而无需重启容器。2. 使用Sidecar容器:在Kubernetes等容器编排系统中,可以为应用程序添加一个Sidecar容器,专门用于管理应用程序的更新。Sidecar容器可以监...

delphi2010,delphi2010下载

delphi2010,delphi2010下载

Delphi 2010是由Embarcadero公司发布的一个集成开发环境(IDE),主要特点如下:1. 编译器改进:Delphi 2010引入了新的编译器,支持更多的语言特性和编译器指令。2. 现代化IDE:IDE更加现代化,支持更多的开发功能,如代码重构和调试器。3. 数据库支持:支持更多的数据...

有关go的短语,go的短语归纳大全初中

有关go的短语,go的短语归纳大全初中

1. Go ahead 请继续,往前走2. Go for it 尽管去做,试试看3. Go with the flow 顺其自然,随波逐流4. Go the extra mile 额外努力,做得更多5. Go out on a limb 冒险尝试,承担风险6. Go back to squ...

r语言不等于,深入解析与使用技巧

在R语言中,不等于的运算符是 `!=` 或者 ``。例如,如果你有两个变量 `a` 和 `b`,你可以使用以下方式来检查它们是否不相等:```Ra != b 使用 != 运算符a b 使用 运算符```这两种方式都是有效的,不过 `` 运算符在R语言中不是特别常用,它主要来源于其他编程语...