数据结构与算法-二叉树的遍历(含非递归)

二叉树遍历的非递归算法 非递归的算法主要采用的是循环出栈入栈来实现对二叉树的遍历,下面是过程分析 阅读详情

二叉树的遍历

树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次,我们把这种对所有节点的访问称为遍历(traversal)。那么树的两种重要的遍历模式是深度优先遍历和广度优先遍历,深度优先一般用递归,广度优先一般用队列。一般情况下能用递归实现的算法大部分也能用堆栈来实现。

 

广度优先遍历(层次遍历)

从树的root开始,从上到下从从左到右遍历整个树的节点

class Node(object):
    """节点类"""
    def __init__(self, elem=-1, lchild=None, rchild=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild

class Tree(object):
    """树类"""
    def __init__(self, root=None):
        self.root = root

    def add(self, elem):
        """为树添加节点"""
        node = Node(elem)
        #如果树是空的,则对根节点赋值
        if self.root == None:
            self.root = node
        else:
            queue = []
            queue.append(self.root)
            #对已有的节点进行层次遍历
            while queue:
                #弹出队列的第一个元素
                cur = queue.pop(0)
                if cur.lchild == None:
                    cur.lchild = node
                    return
                elif cur.rchild == None:
                    cur.rchild = node
                    return
                else:
                    #如果左右子树都不为空,加入队列继续判断
                    queue.append(cur.lchild)
                    queue.append(cur.rchild)

    def breadth_travel(self, root):
        """利用队列实现树的层次遍历"""
        if root == None:
            return
        queue = []
        queue.append(root)
        while queue:
            node = queue.pop(0)
            print node.elem,
            if node.lchild != None:
                queue.append(node.lchild)
            if node.rchild != None:
                queue.append(node.rchild)

深度优先遍历

对于一颗二叉树,深度优先搜索是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
那么深度遍历有重要的三种方法。这三种方式常被用于访问树的节点,它们之间的不同在于访问每个节点的次序不同。这三种遍历分别叫做先序遍历(preorder),中序遍历(inorder)和后序遍历(postorder)

  • 先序遍历 在先序遍历中,我们先访问根节点,然后递归使用先序遍历访问左子树,再递归使用先序遍历访问右子树
    根节点->左子树->右子树
  • 中序遍历 在中序遍历中,我们递归使用中序遍历访问左子树,然后访问根节点,最后再递归使用中序遍历访问右子树
    左子树->根节点->右子树
  • 后序遍历 在后序遍历中,我们先递归使用后序遍历访问左子树和右子树,最后访问根节点
    左子树->右子树->根节点

简单的来说就像下图一样

上图所示:

先序遍历的顺序为:0,1,2

中序遍历的顺序为:1,0,2

后序遍历的顺序为:1,2,0

那么结合代码来看一下,就非常清楚了

class Node(object):
    """节点类"""
    def __init__(self, elem=-1, lchild=None, rchild=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild

class Tree(object):
    """树类"""
    def __init__(self, root=None):
        self.root = root

    def add(self, elem):
        """为树添加节点"""
        node = Node(elem)
        #如果树是空的,则对根节点赋值
        if self.root == None:
            self.root = node
        else:
            queue = []
            queue.append(self.root)
            #对已有的节点进行层次遍历
            while queue:
                #弹出队列的第一个元素
                cur = queue.pop(0)
                if cur.lchild == None:
                    cur.lchild = node
                    return
                elif cur.rchild == None:
                    cur.rchild = node
                    return
                else:
                    #如果左右子树都不为空,加入队列继续判断
                    queue.append(cur.lchild)
                    queue.append(cur.rchild)

    def breadth_travel(self, root):
        """利用队列实现树的层次遍历"""
        if root == None:
            return
        queue = []
        queue.append(root)
        while queue:
            node = queue.pop(0)
            print node.elem,
            if node.lchild != None:
                queue.append(node.lchild)
            if node.rchild != None:
                queue.append(node.rchild)

    def preorder(self, root):
        """递归实现先序遍历"""
        if root == None:
            return
        print root.elem
        self.preorder(root.lchild)
        self.preorder(root.rchild)
    
    def inorder(self, root):
        """递归实现中序遍历"""
        if root == None:
            return
        self.inorder(root.lchild)
        print root.elem
        self.inorder(root.rchild)

    def postorder(self, root):
        """递归实现后续遍历"""
        if root == None:
            return
        self.postorder(root.lchild)
        self.postorder(root.rchild)
        print root.elem

    

上面是递归的写法,那下面我们来讨论一下非递归又该怎么去实现二叉树的前中后序的遍历呢?

重点:非递归遍历二叉树

三种方法都很巧妙

详细看代码示例

class Node(object):
    """二叉树节点"""
    def __init__(self, item):
        self.elem = item
        self.lchild = None
        self.rchild = None


class Tree(object):
    """二叉树"""
    def __init__(self):
        self.root = None

    def add(self, item):
        node = Node(item)
        if self.root is None:
            self.root = node
            return
        queue = [self.root]
        while queue:
            cur_node = queue.pop(0)
            if cur_node.lchild is None:
                cur_node.lchild = node
                return
            else:
                queue.append(cur_node.lchild)
            if cur_node.rchild is None:
                cur_node.rchild = node
                return
            else:
                queue.append(cur_node.rchild)


    def breadth_travel(self):
        """广度遍历(层次遍历)"""
        if self.root is None:
            return
        queue = [self.root]
        while queue:
            cur_node = queue.pop(0)
            print(cur_node.elem, end=" ")
            if cur_node.lchild is not None:
                queue.append(cur_node.lchild)
            if cur_node.rchild is not None:
                queue.append(cur_node.rchild)

    def preorder(self, node):
        """先序遍历"""
        if node is None:
            return
        print(node.elem,end=" ")
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    def inorder(self, node):
        """中序遍历"""
        if node is None:
            return
        self.inorder(node.lchild)
        print(node.elem, end=" ")
        self.inorder(node.rchild)

    def postorder(self, node):
        """后序遍历"""
        if node is None:
            return
        self.postorder(node.lchild)
        self.postorder(node.rchild)
        print(node.elem, end=" ")

    def preOrderUnRecur(self,node):
        """
            ## 先序遍历非递归方式实现
            原理是利用一个栈,先压入根节点,然后当栈不为空的时候,循环执行以下过程:
            1. 先从栈中弹出一个元素,并打印
            2. 然后判断右子树为不为空,不为空,将右子树压入栈中
            3. 然后判断左子树为不为空,不为空,将左子树压入栈中
            因为栈是先进后出的 所以是 先右子树进栈,再左子树,即 (右,左) 的顺序。那么出栈的时候就是,先打印中,然后出左,再出右,一直循环,从而实现先序遍历(中左右)
        """
        if node is None:
            return
        stack = [] #定义一个栈
        stack.append(node)
        while len(stack):
            pop_node = stack.pop()
            print(pop_node.elem, end=" ")
            if pop_node.rchild is not None:
                stack.append(pop_node.rchild)
            if pop_node.lchild is not None:
                stack.append(pop_node.lchild)

        print("")

    def inOrderUnRecur(self, node):
        """
            ## 中序遍历非递归方式实现
        """
        if node is None:
            return
        stack = [] #定义一个栈
        while len(stack) or node is not None: #当根节点不为空或者栈不为空的时候进入

            if node is not None: #当前节点不为空,当前节点入栈,当前节点往左子树移动 导致一次就压入左边的一整个边线 所以 出栈的时候 是左中右
                stack.append(node)
                node = node.lchild
            else: # 当前节点为空,从栈中拿出一个,打印,当前节点往右子树移动
                node = stack.pop()
                print(node.elem,end=" ")
                node = node.rchild

        print("")

    def posOrderUnRecur(self, node):
            """
                ## 后序遍历非递归方式实现
                原理是利用两个栈,先压入根节点,然后当栈不为空的时候,循环执行以下过程:
                1. 先从第一个栈中弹出一个元素,压入第二个栈(中)
                2. 然后判断左子树为不为空,不为空,将左子树压入栈中
                3. 然后判断右子树为不为空,不为空,将右子树压入栈中
                先压左 ,再压右 后面出来就是右,左 ,压入到第二个栈就是 (左,右)
                从而,第二个栈的栈里存的是中右左,出栈就是(左右中) 实现后序遍历
            """
            if node is None:
                return
            stack1 = []  # 定义第一个栈
            stack2 = []  # 定义第二个栈
            stack1.append(node)
            while len(stack1):
                pop_node = stack1.pop()
                stack2.append(pop_node) # 参照先序遍历的时候是拿出来打印的,现在压到另一个栈中, 压入第二个栈的是(中)
                if pop_node.lchild is not None: #然后先压左 ,再压右 后面出来就是右,左 ,压入到第二个栈就是 (左,右)
                    stack1.append(pop_node.lchild)
                if pop_node.rchild is not None:
                    stack1.append(pop_node.rchild)

            while len(stack2):
                pop2_node = stack2.pop()
                print(pop2_node.elem, end=" ")

            print("")

if __name__ == '__main__':
    tree = Tree()
    tree.add(1)
    tree.add(2)
    tree.add(3)
    tree.add(4)
    tree.add(5)
    tree.add(6)
    tree.add(7)
    tree.breadth_travel()
    print(" ")
    tree.preorder(tree.root) # 递归方式: 1 2 4 5 3 6 7
    print(" ")
    tree.preOrderUnRecur(tree.root) # 非递归方式: 1 2 4 5 3 6 7

    tree.inorder(tree.root) # 递归方式: 4 2 5 1 6 3 7
    print(" ")
    tree.inOrderUnRecur(tree.root) # 非递归方式: 4 2 5 1 6 3 7


    tree.postorder(tree.root) #递归方式: 4 5 2 6 7 3 1
    print(" ")
    tree.posOrderUnRecur(tree.root) # 非pos递归方式: 4 5 2 6 7 3 1

至此,二叉树的遍历就讲完全了,可以轻松解决面试题如:

题:实现二叉树的先序、中序、后序遍历,包括递归方式和非递归方式

 

 

 

二叉树遍历,栈实现二叉树的非递归遍历 另见求树高 http://blog.youkuaiyun.com/Justme0/article/details/7694704 /******************************************************************** created: 2014/05/11 23:13 filename: main.c author: Just 阅读详情

相关推荐

数据结构5.11二叉树的非递归遍历算法

本节主要前面二叉树的递归遍历基础上,讲述二叉树的非递归遍历方法。

最全的树的遍历算法(递归和非递归)

树的算法如下:非递归的算法中,中序和后续遍历稍微难写一些 ,需要多练。其余的基本是模板方式,多横向对比感受下。 import java.util.Stack; public class SearchTree { public static void main(String[] args) { BinaryTreeNode root = new BinaryTreeN...

战斗小火鸡 883

数据结构 二叉树三种遍历的非递归算法(背诵版).doc

数据结构 二叉树三种遍历的非递归算法(背诵版). 数据结构 二叉树三种遍历的非递归算法(背诵版). 数据结构 二叉树三种遍历的非递归算法(背诵版).

树的广度优先遍历(非递归)和深度优先遍历

package leetcode.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Scanner; public class MaxSum { public static void main(String[] args) { MaxSum

shenxingbo的专栏 1073

RK3588 C-PHY摄像头驱动升级踩坑记:从‘Only CSI2 supported’报错到成功取流

本文详细记录了在RK3588平台上调试C-PHY摄像头驱动的全过程,从‘Only CSI2 supported’报错分析到成功取流。内容涵盖C-PHY与CSI-2协议差异、SDK版本对比、V4L2框架下的bus-type解析机制,以及硬件排查与寄存器调优实战经验,为嵌入式Camera驱动工程师提供宝贵参考。

weixin_42522374的博客 125

统信UOS系统盘扩容保姆级教程:用GParten-分区编辑器5分钟搞定

本文提供统信UOS系统盘扩容的详细图形化教程。针对系统盘空间不足问题,重点介绍如何使用系统自带的GParten-分区编辑器,在5-10分钟内安全、直观地完成扩容操作,无需记忆复杂命令,适合所有用户快速解决存储空间告急的困扰。

e3f4g5的博客 645

非递归实现二叉树遍历(附c++完整代码)

先序、中序和后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同。 从图中可以看到,前序遍历在第一次遇见元素时输出,中序遍历在第二次遇见元素时输出,后序遍历在第三次遇见元素时输出。 非递归算法实现的基本思路:使用堆栈 一、前序遍历 1、递归实现 遍历过程为: 访问根结点; 先序遍历其左子树; 先序遍历其右子树。 void ProOrderTraverse(BiTree tre...

桑凯旋的博客 2万+

普冉PY32F002B ADC内部参考电压VREFINT的误差补偿与低功耗优化实践

本文详细介绍了普冉PY32F002B单片机在锂电池供电场景下ADC内部参考电压VREFINT的误差补偿与低功耗优化实践。通过分析GPIO配置、分压电阻匹配、采样时间设置等硬件设计要点,结合实时测量VREFINT电压值和软件补偿算法,有效提升了ADC测量精度至5mV以内,并实现了分压电路功耗控制与采样频率优化,为低成本消费电子项目提供了完整的解决方案。

847

C语言经典算法之二叉树的前序遍历(非递归实现)

在C语言中,二叉树的前序遍历(根-左-右)非递归实现通常使用栈来辅助。

weixin_56154577的博客 2449

基于Opencv+Mediapipe的头部姿态检测

在学生课堂专注度检测项目中,可以通过学生头部姿态来确定学生注意力方向,从而判断其是否专注于课堂。

weixin_67879842的博客 2338

汽车级智能栅极驱动器深度解析 | 连载03:功能框图与工作模式详解

在前两期连载中,我们分析了DRV871x-Q1的产品架构、引脚配置和电气特性。本期我们将深入探讨DRV871x-Q1的功能框图和工作模式,这是理解芯片内部工作机制的关键。通过分析功能框图,我们能够清晰地了解各功能模块之间的关系和信号流向;通过工作模式分析,我们能够掌握芯片在不同应用场景下的配置方法。这些知识对于系统设计和故障排查都至关重要。

VehSwHwDeveloper的博客 1103

高级数据结构与算法——二叉树的四种遍历算法(含非递归)

文章目录二叉树的遍历定义前序遍历递归算法非归算法中序遍历递归算法非递归算法后序遍历递归算法 二叉树的遍历定义   所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。   其中搜索路线我们这里介绍4中:前序遍历,中序遍历,后续遍历,层次遍历。 前序遍历 ...

T、的博客 623

[PCIE5.0] 4.2.3.2 Encoding of Presets

• 发射器预设:发射器预设值用4位二进制编码,表示不同的预设设置(P0 到 P10),这些设置定义了信号的传输特性。• 接收器预设提示:接收器预设提示是通过3位二进制编码告诉接收器建议的增益值,用于调整接收器的灵敏度(适用于8.0 GT/s数据速率)。

系统固件工程师 575

数据结构与算法问题 二叉树的建立与遍历(含非递归)

二叉树的非递归遍历          二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说

Leviathan_的专栏 1139

抓包工具:Fiddler下载、安装、使用 教程

文章目录抓包工具:Fiddler下载、安装、使用 教程一、Fiddler 下载二、Fiddler 安装三、Fiddler 使用3、Statistics 请求的性能数据分析4、Inspectors 查看数据内容5、AutoResponder 允许拦截指定规则的请求6、Composer 自定义请求发送服务器7、Filters 请求过滤规则8、Timeline 请求响应时间9、Fiddler 设置解密HTTPS的网络数据10、Fiddler 内置命令与断点 抓包工具:Fiddler下载、安装、使用 教程 Fidd

Sumarua的博客 17万+

【目标检测-YOLO】YOLOv5-v5.0-yolov5s网络架构详解(第一篇)

源码:GitHub - ultralytics/yolov5 at v5.0 由于YOLO v5 代码库在持续更新,如上图,有多个版本,每个版本的网络结构不尽相同。以下内容以 v5.0 为准,网络结构选用 yolov5s。 为了方便画图和理解网络结构,选用可视化工具:Netron 网页版进行可视化, 然后使用PPT作图。 在Releases · ultralytics/yolov5 · GitHub找到 v5.0中的Assets 中的yolov5s.pt并下载该权重。 下图为直接......

博观约取,厚积薄发 2万+

二叉树的中序遍历非递归算法

*非递归算法思想:    (1)设置一个栈S存放所经过的根结点(指针)信息;初始化S;   (2)第一次访问到根结点并不访问,而是入栈;    (3)中序遍历它的左子树,左子树遍历结束后,第二次遇到根结点,就将根结点(指针)退栈,并且访问根结点;然后中序遍历它的右子树。   (4) 当需要退栈时,如果栈为空则结束。           代码实现: void ...

Billy1900的博客 4万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

二叉树的非递归遍历

二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。 ​ 三种遍历方式访问节点的顺序是一致的,不同之处在于,有的遍历流程把访问到的节点暂存起来,达成某种条件后再将节点输出。

qq_43169752的博客 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【数据结构】二叉树之非递归遍历

本篇使用例题图解二叉树链式结构的非递归前、中、后序遍历。o(* ̄▽ ̄*)ブ

阿琪 2423

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【数据结构与算法】二叉树的非递归前中后序遍历

二叉树的前中后遍历如果采取递归的方式来实现,是相当容易的事情。递归之所以强大,是因为有系统自动压栈。那么非递归的前中后序遍历就是借助栈,通过我们自己手动压栈来实现二叉树的遍历。

joy.728的博客 1458

二叉树:中序遍历非递归与递归算法

二叉树(BiTree)的遍历分为: 先序遍历(preorder):根左右 中序遍历(inorder):左根右 后序遍历(postorder):左右根 其中,时间复杂度和空间复杂度都是O(n), 二叉树的遍历递归算法不常考,主要考察非递归❤ 先序、中序、后序遍历(递归) 递归算法的区别在于visit()函数的位置❤,代码以先序遍历为例,其顺序为根左右,if判断语句中符合这一规律,中序、后序按其左根右和左右根的规律改变这三句代码的顺序即可。 void preorder(BiTree T){ // 先序遍历递.

花间半盘棋 4886

二叉树的中序非递归遍历

二叉树的中序非递归遍历 中序遍历的非递归算法描述如下: 从根节点开始检索,如果当前节点不为空,则将当前节点入栈,让当前节点成为其左孩子节点,再继续上一步的操作 加入当前节点为空了,说明其父节点已经没有左孩子了,那么将栈顶元素出栈并输入 判断栈顶元素是否有右孩子,如果有右孩子,则停止依次继续出栈的操作,并检索它的右孩子,重复第一步;如果没有右孩子,则继续将栈顶元素出栈 当栈为空,并且当前节点为空时,遍历完成,退出; #include<stdio.h> #include<stdlib.h&

weixin_45863060的博客 8773

二叉树遍历非递归算法

给大家一个效率较高的后序遍历非递归算法(c语言编写,本算法不需要改变二叉树的结点结构):typedef struct node  { /*二叉树的结点存储类型为链式*/    char data;    struct node *lchild,*rchild;}node,*btree;void backordertraverse(btree t)  {  /*用栈标记法(本人喜欢这样叫)*/   

青青的专栏--C/C++ OOA/D Design Pattern 4140

【数据结构】非递归实现二叉树的先序遍历

非递归实现二叉树的先序遍历

每天进步一点丶的博客 4504

[数据结构]对中序非递归遍历二叉树的理解与讨论

中序遍历二叉树,即是先遍历左子树,再访问根节点,最后遍历右子树,这个顺序对于每棵子树都是一样的,是访问子树的共性,故可依次顺序设置循环,逐一访问每个结点。对于每一个树的子树,均要完成此操作。故在开始遍历之时,应先找到最左边的结点,遍历应从此开始。访问完此结点,应逐一访问此结点的根结点和右子树。有点难度的第一是找最左节点。方法是从树的根结点顺lchild而下直到NULL为止。二是访问完根节点后以中序

飞鱼天空 6700
上一篇: 数据结构与算法-二叉树
下一篇: 数据结构与算法-求二叉树某个节点的前驱节点与后继节点
LELELED
博客等级 码龄9年 3粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值