最近工作忙,没时间思考复杂的问题了。正好要招人就得有面试的嘛,自己也温习一下,要不然怎么去问别人。

今天复习一下二叉树的遍历,前序(pre-order,NLR)、中序(in-order,LNR)、后序(post-order,LRN)、层序(level-order),用和不用递归。

概念就不用多解释了,前、中、后是指根结点的访问时机,在左、右子树之前、中间、或之后。层序就是从根结点开始从上至下、从左到右地依次访问。

一棵二叉树

如上图所示的一棵二叉树,对应的遍历结果分别是:

  • 前序(NLR):A B D C E G H F I
  • 中序(LNR):D B A G E H C F I
  • 后序(LRN):D B G H E I F C A
  • 层序:A B C D E F G H I

一、用递归处理二叉树的前序、中序和后序遍历

递归真是一个迷人东西,它可以把复杂的逻辑变得异常简洁,这也是自然界的表现形式之一。基于递归的前、中、后序遍历二叉树的程序几乎完全相同,用两个递归调用分别处理左、右子树,剩下的事情就是打印根结点。为节省篇幅,直接把三个程序写在一起,用一个参数来控制是哪种遍历方式,也可以更方便地看出三者之间的区别。

1
2
3
4
5
6
7

def VisitTree_Recursive(root, order):if root:if order == 'NLR': print(root.data)VisitTree_Recursive(root.left, order)if order == 'LNR': print(root.data)VisitTree_Recursive(root.right, order)if order == 'LRN': print(root.data)

二、非递归的前序、中序遍历

如果不用递归呢?实际上我们要做的就是自己维护一个栈(数据结构)来保存需要但尚未来得及处理的数据。

前序和中序都是非常简单的,当遇到一个非空的根结点时,打印其数据(如果是前序遍历),并将其压栈,然后递归地(这里用循环来模拟递归)处理其左子结点;当没有左子结点时,从栈中弹出之前遇到的某个根结点(它没有左子结点,或者左子结点已经处理完毕,需要再处理右子结点),打印数据(如果是中序遍历),然后继续处理右子结点。同样地,把两种遍历方式写在一起以便比较。

 123456789
10
11

def VisitTree(root, order):s = []while root or s:if root:if order == 'NLR': print(root.data)s.append(root)root = root.leftelse:root = s.pop()if order == 'LNR': print(root.data)root = root.right

三、非递归的后序遍历

后序遍历要稍微复杂一点点,在前序和中序遍历的程序中,当我们准备进入根结点的右子树时,根结点就被扔出栈外了。但在后序遍历时,我们仍需保留它,直到右子树处理完毕。

首先想到的改动就是在上面的程序的第9行到11行,不要从栈s中将根结点弹出,而是直接开始处理右子结点。但这就会带来一个问题:什么时候弹出根结点?实际上当左子树遍历完成、或者右子树遍历完成时,我们都会在栈里看到根结点,为了区分这两种状态,添加一个临时变量记录前一次访问的结点,如果前一个结点是根结点的右子树,就说明左右子树全都遍历完成了。非常简单。

 123456789
10
11
12
13

def VisitTreeLRN(root):s = []pre = Nonewhile root or s:if root:s.append(root)root = root.leftelif s[-1].right != pre:root = s[-1].rightpre = Noneelse:pre = s.pop()print(pre.data)

四、非递归的层序遍历

层序遍历可以写成递归吗?还真没研究过。非递归的时候,层序遍历使用的是队列,而非栈。

处理过程非常简明,遇到一个结点,打印信息,然后依次将左、右子结点加入队列等待后续处理。

 123456789
10

from collections import dequedef VisitTree_LevelOrder(root):if not root: returnq = deque([root])while q:root = q.popleft()print(root.data)if root.left: q.append(root.left)if root.right: q.append(root.right)

附录

上面的python代码基于v2.7。另外可以用下面这段代码来定义最简单的二叉树结点类,生成最上面图示的二叉树:

 123456789
10
11
12
13
14
15
16

class Node:def __init__(self, data, left = None, right = None):self.data = dataself.left = leftself.right = rightg = Node('G')
h = Node('H')
e = Node('E', g, h)
i = Node('I')
f = Node('F', None, i)
c = Node('C', e, f)
d = Node('D')
b = Node('B', d)
a = Node('A', b, c)
root = a

程序基本功之遍历二叉树相关推荐

  1. 遍历二叉树的各种操作(非递归遍历)

    先使用先序的方法建立一棵二叉树,然后分别使用递归与非递归的方法实现前序.中序.后序遍历二叉树,并使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组 ...

  2. 【转】更简单的非递归遍历二叉树的方法

    [转]更简单的非递归遍历二叉树的方法 解决二叉树的很多问题的方案都是基于对二叉树的遍历.遍历二叉树的前序,中序,后序三大方法算是计算机科班学生必写代码了.其递归遍历是人人都能信手拈来,可是在手生时写出 ...

  3. 广度优先遍历二叉树(BFS)-C++实现

    1 // 广度优先遍历二叉树(BFS).cpp: 定义控制台应用程序的入口点.2 //3 4 #include "stdafx.h"5 6 7 #include <iostr ...

  4. 遍历二叉树的全部方法(递归+非递归)

    #include<iostream> #include<queue> #include<stack> using namespace std; //二叉树结点的描述 ...

  5. 【数据结构】——构建二叉树,遍历二叉树

    二叉树的数据结构: 1 typedef struct BiTree{ 2 char item; 3 struct BiTree *lchild,*rchild; 4 }BiTree; 构建一个二叉树: ...

  6. 数据结构入门----遍历二叉树和线索二叉树

    遍历二叉树(Traversing Binary Tree) 二叉树的遍历是指从根结点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次. 实际应用中,查找树中符合条件的结点 ...

  7. 8.遍历二叉树、线索二叉树、森林

    思考 一.什么遍历二叉树.线索二叉树.森林?(What) 0.二叉树遍历一共(4种) 1.二叉树先序遍历 2.二叉树中序遍历 3.二叉树后序遍历 4.遍历分析 5.遍历二叉树 6.二叉树层次遍历 7. ...

  8. 更简单的非递归遍历二叉树

    解决二叉树的很多问题的方案都是基于对二叉树的遍历.遍历二叉树的前序,中序,后序三大方法算是计算机科班学生必写代码了.其递归遍历是人人都能信手拈来,可是在手生时写出非递归遍历恐非易事.正因为并非易事,所 ...

  9. C实现前序遍历二叉树

    1. 实验目的 (1)掌握二叉树的逻辑结构: (2)掌握二叉树的二叉链表存储结构: (3)验证二叉树的二叉链表存储及遍历操作. 2. 实验目的 (1)建立一棵含有n个结点的二叉树,采用二叉链表存储: ...

最新文章

  1. Python之print语句Python的注释
  2. 快速撑握C#知识点系列之(struct)结构
  3. ndpi 流量协议分析
  4. 机器人学习--Turtelbot3学习-- Burger与waffle等版本的切换
  5. Actor并发模型入门
  6. 为什么说spark不稳定
  7. 华为android怎样隐藏软件,华为怎么打开隐藏应用功能
  8. wincc历史数据库_WinCC系统的基本功能介绍——自动化工程师必备
  9. Atitit.运行cmd 命令行 php
  10. Newtonsoft.Json.dll 使用
  11. UI设计素材|图标在UI设计界面当中起到什么作用
  12. 找出只出现一次的第一个字符
  13. php buildconf,PHP Extension开发 Unix Build System配置 conf
  14. python基于django的高校教师科研成果管理系统
  15. C#使用struct直接转换下位机数据的示例代码
  16. python爬取ajax_Python爬虫如-何爬取ajax网页之爬取雪球网文章
  17. 一次因JDK夏令时导致接口输出日期格式的时间与预期时间不一致的bug排查
  18. 高分一号WFV影像云检测工具(免费)
  19. mac 访问局域网其他电脑上的虚拟机
  20. 基于Netty的UDP服务端开发

热门文章

  1. 【鸿蒙 HarmonyOS】UI 组件 ( Text 组件 )
  2. php 数学函数bc的使用(浮点数计算)
  3. zabbix系列之九——添加钉钉告警
  4. 根据 中序遍历 和 后序遍历构造树(Presentation)(C++)
  5. POJ 3525/UVA 1396 Most Distant Point from the Sea(二分+半平面交)
  6. POJ-2195 Going Home 最小权值匹配
  7. OpenDataSource,sql开放式数据源
  8. Silverlight教程第四部分:使用 Style 元素更好地封装观感 (木野狐译)
  9. C程序多线程同时画圆画方
  10. Android系统分区理解及分区目录细解