算法小抄10-二叉树的遍历方式

上节中我们学到了链表,这一节中学习一个新的数据结构二叉树,对于链表它拥有的属性时值val,和下一个链表节点指针next,而二叉树其实就比他多一个属性,它的形状看起来是下面这样的:

class TreeNode:
    def __init__(self, val=0, left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
    
head=TreeNode(1,TreeNode(2),TreeNode(3))
print(head.val)#1
print(head.left.val)#2
print(head.right.val)#3

这样的方式组成的二叉树如下图所示:

和之前一样,我们先介绍二叉树的遍历方式

二叉树的遍历

二叉树的有三种递归遍历方式和一种层序遍历方式,都是需要掌握的,我们使用如下图所示的二叉树来进行讲解:

前序遍历

前序遍历的方式是<根,左,右>的遍历方式,因为先遍历根节点所以叫前序遍历,根据上述二叉树,从根节点1出发,那么整体二叉树会输出成什么样呢?这里我们先给出代码,根据代码来推一推吧:

class TreeNode:
    def __init__(self, val=0, left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
    @staticmethod
    def pre_order(head):
        if head is None:return
        print(head.val)
        TreeNode.pre_order(head.left)
        TreeNode.pre_order(head.right)

head=TreeNode(1,TreeNode(2,TreeNode(4),TreeNode(5)),TreeNode(3,TreeNode(6),None))
TreeNode.pre_order(head)

答案是1 2 4 5 3 6,有答对嘛,没有答对没有关系,因为这里牵扯到一个新的知识点递归,我们根据当前二叉树来分析一下代码如何运行:

 如下图所示,那个长方形的东西叫做栈,函数是右边那个pre_order,函数只有进栈后才能正确的运行

根据下图来看一下进栈的过程,进入栈后pre_order(1)开始运行,第一句不为空吧,继续往下运行,第二句打印1,第三句涉及到了递归函数,需要创建一个新的函数pre_order(2),也就是pre_order(1.left),而且需要在pre_order(2)进栈运行完成之后再继续第四句代码的运行

继续pre_order(2)进栈后打印2,重复刚刚的过程在第三句的时候创建了pre_order(4)

接着pre_order(4)进栈,打印4重复以上过程创建了pre_order(None),因为对于4这个节点并没有左子节点嘛,对是不对

延续刚刚的过程,pre_order(None)进栈,开始执行代码,在第一句的时候整个代码就已经执行完了,执行完之后的函数会进行出栈操作

出栈后我们栈顶的函数为pre_order(4),还记得上次这个函数运行到哪行代码了吗?是第三句哦,所以现在会继续运行第四句代码,4这个节点是不是依然没有右节点,那么生成的函数还是pre_order(None),和上述过程完全一样,这里就不再赘述了,我们继续往下看

在又一个pre_order(None)出栈之后,pre_order(4)也全部执行结束了,所以pre_order(4)也该出栈

 接着看,在pre_order(4)出栈后,栈顶的函数是pre_order(2),这个函数上次也是执行到第三句话,该接着执行第四句代码了,这里又创建了一个函数pre_order(5),因为2的右节点是5嘛

 接着pre_order(5)入栈打印5,最后再开始打印节点1的右节点,分析的过程和我们上面是一样的哦,羊羊可以自己分析一下

最后的打印结果就是1,2,4,5,3,6了

中序遍历

理解了递归和前序遍历,中序遍历就显得十分简单了,它的代码如下,只是输出语句换了一个位置罢了:

class TreeNode:
    def __init__(self, val=0, left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
    @staticmethod
    def in_order(head):
        if head is None:return
        TreeNode.in_order(head.left)
        print(head.val)
        TreeNode.in_order(head.right)

head=TreeNode(1,TreeNode(2,TreeNode(4),TreeNode(5)),TreeNode(3,TreeNode(6),None))
TreeNode.in_order(head)

他的输出结果是:4 2 5 1 6 3,因为他的打印方式是《左,根,右》会最先输出左子树的节点

后序遍历

是不是已经可以自己写出后序遍历了,真的很简单呢

class TreeNode:
    def __init__(self, val=0, left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
    @staticmethod
    def post_order(head):
        if head is None:return
        TreeNode.post_order(head.left)
        TreeNode.post_order(head.right)
        print(head.val)

head=TreeNode(1,TreeNode(2,TreeNode(4),TreeNode(5)),TreeNode(3,TreeNode(6),None))
TreeNode.post_order(head)

他的输出结果是:4 5 2 6 3 1

随堂检测

不借助代码能否写出如下这颗树的前序,中序和后续遍历呢,后续自己可以使用代码来测试一下哦:

层序遍历

是不是感觉前中后序遍历都没有什么规律可言,好像是给电脑看的,我作为一个人我就想遍历出来就是1,2,3,4,5,6,7,8这样的,这就要说到层序遍历了

其思路是这样的,我们先将头节点放入容器,然后在遍历到头节点的左节点和右节点的时候也将其加入容器,在一个节点的左节点和右节点都被遍历完以后将这个节点丢出容器,现在容器里是不是只剩下头节点的左右节点了,我们继续上述操作,按照先来先到的原则,对这两个节点执行上述操作,直到容器内什么都不剩下

思考一下要找到最先进入的节点我们该使用什么数据结构呢?栈的特点(先序遍历的时候讲过了,栈只有一个口子进出)是先进后出与我们的用法相悖,所以该使用的是队列(队列是一个先进先出的数据结构,像一根管子一样,add函数从管子的头进入,poll函数从管子的后面取出,python中的栈和队列都是用deque双端队列来实现的,这里要记得import哦)

import collections #别忘记导入容器工具

class TreeNode:
    def __init__(self, val=0, left=None,right=None):
        self.val = val
        self.left = left
        self.right = right

    @staticmethod
    def post_order(head):
        if head is None:return
        TreeNode.post_order(head.left)
        TreeNode.post_order(head.right)
        print(head.val)

    @staticmethod
    def levelOrder(root):
        if root == None: return [] # 特判
        que = collections.deque([root]) # 双端队列,初始化并且将root丢进队列
        ans = []
        while len(que) != 0:
            size = len(que)
            level = []
            for _ in range(size): # 遍历当前层节点
                cur = que.popleft() # 从左边弹出队列
                level.append(cur.val) # 将当前节点值加入当前层的列表
                if cur.left != None: que.append(cur.left)
                if cur.right != None: que.append(cur.right)
            ans.append(level) # 将当前层结果加入答案列表
        return ans

    @staticmethod
    def printList(list):
        for subList in list:
            print(subList)
            
head=TreeNode(1,TreeNode(2,TreeNode(4),TreeNode(5)),TreeNode(3,TreeNode(6),None))
ans=TreeNode.levelOrder(head)
TreeNode.printList(ans)

结果打印出来如下图所示:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Leetcode算法是一份权威的算法手册,包含了Leetcode上常见的算法题目的解法和详细讲解。这个小对于想要提升自己算法能力的程序员来说非常有用。该小包括以下内容: 1.基础数据结构:包括数组、链表、栈、队列、树、哈希表等。 2.算法基础:包括排序算法、搜索算法、贪心算法、动态规划等。 3.高级算法:包括图论、字符串匹配、线性代数、计算几何等。 每个算法题目都附有详细的解析和代码实现,方便程序员进行学习和练习。此外,该小还提供了优秀的算法实现其他程序员的思路和解答,这对于新手来说尤为重要。 总之,Leetcode算法是一份非常实用的算法手册,如果你想成为一名出色的程序员,学习和掌握其中的内容必不可少。 ### 回答2: LeetCode算法是一份非常实用的算法指南,它包含了大量的算法问题和解答,而且所有的算法问题都是以LeetCode网站上的题目为蓝本的。这个小主要面向准备参加Google、Facebook、 Apple等知名科技公司的笔试或者面试的程序员,也适用于想要提高自己算法能力的人。这份小的编制者是Steven Halim和Felix Halim,也就是ACM竞赛的著名选手和教练。他们将自己多年的ACM竞赛经验倾囊相授,帮助大家提高算法能力。小中包含了高频出现的数据结构和算法,如树、图、排序、数组、动态规划等,每个算法都有详细的解释和代码实现。此外,小还包含了一些实用技巧,如测试用例设计、代码调试、复杂度分析等。总之,LeetCode算法是一份非常实用、全面的算法指南,如果你想要提高自己的算法能力,相信它一定能为你带来帮助。 ### 回答3: LeetCode算法是一个常用的算法学习工具,它主要是为了帮助程序员更加高效地学习和掌握LeetCode算法。LeetCode算法中收录了大量经典的算法题目,并提供了详细的题解和代码示例,涵盖了各种数据结构、算法和编程技术。 LeetCode算法的优点在于它的简便性和针对性。其内容结构清晰,难度逐渐增加,让读者能够逐步学习并掌握更加复杂的数据结构和算法。同时,小中提供了大量的代码示例和优化方法,可以帮助读者更加深入地理解和掌握算法。 另外,LeetCode算法还提供了各种算法题目的分类、标签和解法推荐,让读者能够更加容易地找到自己需要的题目和解法。同时,小中还提供了一些常见的面试题目和解题思路,可以帮助读者更好地应对工作中和面试中的挑战。 总之,LeetCode算法是一本非常实用的算法学习工具,它可以帮助程序员更加高效地学习和掌握算法知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值