二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的。对于二叉树,有深度遍历和广度遍历,深度遍历有前序、中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历。由于树的定义本身就是递归定义,因此採用递归的方法去实现树的三种遍历不仅easy理解并且代码非常简洁,而对于广度遍历来说,须要其他数据结构的支撑。比方堆了。所以。对于一段代码来说,可读性有时候要比代码本身的效率要重要的多。

四种基本的遍历思想为:

前序遍历:根结点 —> 左子树 —> 右子树

中序遍历:左子树—> 根结点 —> 右子树

后序遍历:左子树 —> 右子树 —> 根结点

层次遍历:仅仅需按层次遍历就可以

比如。求以下二叉树的各种遍历

1

/ \ 2 3

/ \ /

4 5 6

/ \ 7 8

前序遍历:1 2 4 5 7 8 3 6

中序遍历:4 2 7 5 8 1 3 6

后序遍历:4 7 8 5 2 6 3 1

层次遍历:1 2 3 4 5 6 7 8

一、前序遍历

1)依据上文提到的遍历思路:根结点 —> 左子树 —> 右子树,非常easy写出递归版本号:

public void preOrderTraverse1(TreeNode root) {

if (root != null) {

System.out.print(root.val+" ");

preOrderTraverse1(root.left);

preOrderTraverse1(root.right);

}

}

2)如今讨论非递归的版本号:

依据前序遍历的顺序,优先訪问根结点。然后在訪问左子树和右子树。所以。对于随意结点node。第一部分即直接訪问之,之后在推断左子树是否为空,不为空时即反复上面的步骤,直到其为空。若为空。则须要訪问右子树。注意。在訪问过左孩子之后。须要反过来訪问其右孩子。所以,须要栈这样的数据结构的支持。对于随意一个结点node,详细过程例如以下:

a)訪问之,并把结点node入栈。当前结点置为左孩子;

b)推断结点node是否为空,若为空。则取出栈顶结点并出栈,将右孩子置为当前结点;否则反复a)步直到当前结点为空或者栈为空(能够发现栈中的结点就是为了訪问右孩子才存储的)

代码例如以下:

public void preOrderTraverse2(TreeNode root) {

LinkedList stack = new LinkedList<>();

TreeNode pNode = root;

while (pNode != null || !stack.isEmpty()) {

if (pNode != null) {

System.out.print(pNode.val+" ");

stack.push(pNode);

pNode = pNode.left;

} else { //pNode == null && !stack.isEmpty()

TreeNode node = stack.pop();

pNode = node.right;

}

}

}

二、中序遍历

1)依据上文提到的遍历思路:左子树 —> 根结点 —> 右子树,非常easy写出递归版本号:

public void inOrderTraverse1(TreeNode root) {

if (root != null) {

inOrderTraverse1(root.left);

System.out.print(root.val+" ");

inOrderTraverse1(root.right);

}

}

2)非递归实现,有了上面前序的解释,中序也就比較简单了。同样的道理。仅仅只是訪问的顺序移到出栈时。代码例如以下:

public void inOrderTraverse2(TreeNode root) {

LinkedList stack = new LinkedList<>();

TreeNode pNode = root;

while (pNode != null || !stack.isEmpty()) {

if (pNode != null) {

stack.push(pNode);

pNode = pNode.left;

} else { //pNode == null && !stack.isEmpty()

TreeNode node = stack.pop();

System.out.print(node.val+" ");

pNode = node.right;

}

}

}

三、后序遍历

1)依据上文提到的遍历思路:左子树 —> 右子树 —> 根结点。非常easy写出递归版本号:

public void postOrderTraverse1(TreeNode root) {

if (root != null) {

postOrderTraverse1(root.left);

postOrderTraverse1(root.right);

System.out.print(root.val+" ");

}

}

2)后序遍历的非递归实现是三种遍历方式中最难的一种。由于在后序遍历中,要保证左孩子和右孩子都已被訪问而且左孩子在右孩子前訪问才干訪问根结点,这就为流程的控制带来了难题。以下介绍两种思路。

第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索。直到搜索到没有左孩子的结点,此时该结点出如今栈顶,可是此时不能将其出栈并訪问,因此其右孩子还为被訪问。

所以接下来依照同样的规则对其右子树进行同样的处理,当訪问完其右孩子时。该结点又出如今栈顶,此时能够将其出栈并訪问。这样就保证了正确的訪问顺序。能够看出,在这个过程中,每一个结点都两次出如今栈顶,仅仅有在第二次出如今栈顶时,才干訪问它。因此须要多设置一个变量标识该结点是否是第一次出如今栈顶。

void postOrder2(BinTree *root) //非递归后序遍历

{

stack s;

BinTree *p=root;

BTNode *temp;

while(p!=NULL||!s.empty())

{

while(p!=NULL) //沿左子树一直往下搜索。直至出现没有左子树的结点

{

BTNode *btn=(BTNode *)malloc(sizeof(BTNode));

btn->btnode=p;

btn->isFirst=true;

s.push(btn);

p=p->lchild;

}

if(!s.empty())

{

temp=s.top();

s.pop();

if(temp->isFirst==true) //表示是第一次出如今栈顶

{

temp->isFirst=false;

s.push(temp);

p=temp->btnode->rchild;

}

else //第二次出如今栈顶

{

cout<btnode->data<

p=NULL;

}

}

}

}

另外一种思路:要保证根结点在左孩子和右孩子訪问之后才干訪问,因此对于任一结点P。先将其入栈。假设P不存在左孩子和右孩子。则能够直接訪问它;或者P存在左孩子或者右孩子。可是其左孩子和右孩子都已被訪问过了。则相同能够直接訪问该结点。若非上述两种情况。则将P的右孩子和左孩子依次入栈。这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被訪问。左孩子和右孩子都在根结点前面被訪问。

void postOrder3(BinTree *root) //非递归后序遍历

{

stack s;

BinTree *cur; //当前结点

BinTree *pre=NULL; //前一次訪问的结点

s.push(root);

while(!s.empty())

{

cur=s.top();

if((cur->lchild==NULL&&cur->rchild==NULL)||

(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))

{

cout<data<

s.pop();

pre=cur;

}

else

{

if(cur->rchild!=NULL)

s.push(cur->rchild);

if(cur->lchild!=NULL)

s.push(cur->lchild);

}

}

}

四、层次遍历

层次遍历的代码比較简单。仅仅须要一个队列就可以。先在队列中增加根结点。之后对于随意一个结点来说。在其出队列的时候,訪问之。同一时候假设左孩子和右孩子有不为空的。入队列。代码例如以下:

public void levelTraverse(TreeNode root) {

if (root == null) {

return;

}

LinkedList queue = new LinkedList<>();

queue.offer(root);

while (!queue.isEmpty()) {

TreeNode node = queue.poll();

System.out.print(node.val+" ");

if (node.left != null) {

queue.offer(node.left);

}

if (node.right != null) {

queue.offer(node.right);

}

}

}

五、深度优先遍历

事实上深度遍历就是上面的前序、中序和后序。

二叉树深度优先 java_二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历) java实现...相关推荐

  1. java 树 广度优先遍历_Java二进制搜索树遍历操作的详细描述[前,中,后,层次,广度优先遍历]...

    本文介绍了Java二进制搜索树遍历操作. 与您分享以供参考,如下: 前言: 在Java Binary Search Tree Basics的上一节中,我们了解了该树及其相关知识,并对Binary Se ...

  2. 二叉树的操作(前,中,后序遍历也叫深度优先遍历,非空结点的个数)递归实现

    定义一个二叉树的结点 二叉树的前序遍历, 先访问根结点,再访问左,再访问右. 每次访问都要先看根结点是否为空,然后打印根结点,把此时根结点的左结点作为下一次递归的根结点,当把左结点遍历完后,再遍历右结 ...

  3. 二叉树的前、中、后、层次非递归遍历(js)

    有如下二叉树  遍历: // 前序遍历, head-left-rightfunction HLR (tree) {const stack = [], res = []if (tree) stack.p ...

  4. 二叉树前序遍历python输出_[宜配屋]听图阁 - Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例...

    本文实例讲述了Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作.分享给大家供大家参考,具体如下: 实现一个功能: 输入:一颗二叉树的先序和中序遍历 输出:后续遍历 思想: 先序遍历中,第 ...

  5. 二叉树的前序中序后序遍历

    二叉树的前序中序后序遍历 二叉树的遍历 前序遍历 中序遍历 后序遍历 总结 二叉树的遍历 二叉树的遍历有前序遍历,中序遍历,后序遍历三种. 今天我把二叉树的遍历方法给大家总结一下,也算对我自己学习的一 ...

  6. 【二叉树Java】二叉树遍历前序中序后序遍历的非递归写法

    本文主要介绍二叉树前序中序后序遍历的非递归写法 在探讨如何写出二叉树的前序中序后序遍历代码之前,我们先来明确一个问题,前序中序后序遍历根据什么区分? 二叉树的前序中序后序遍历,是相较根节点说的.最先遍 ...

  7. 二叉树的前序中序后序遍历java代码实现

    1.前序遍历概述 前序遍历(VLR) 是二叉树遍历的一种,也叫做先根遍历.先序遍历.前序周游,可记做根左右.前序遍历首先访问根结点然后遍历左子树,最后遍历右子树. 若二叉树为空则结束返回,否则: (1 ...

  8. 二叉树的前序中序后序遍历真题

    一颗二叉树的前序遍历是ABCDFGHE,后序遍历是BGHFDECA,中序遍历是? A.GHBADFCEB.DGBAFHECC.BADGFHCED.BAGDFHEC 正确答案:C 牛客网来源:https ...

  9. 二叉树遍历(递归实现前序/中序/后序遍历)

    1. 准备工作 我们先定义一棵普通的二叉树,如下图 2. 前序遍历 通过递归进行遍历: 如果二叉树为空,则操作返回: 如果非空,否则从根结点开始,然后遍历左子树,再遍历右子树. 前序遍历的结果是:AB ...

  10. C++用类实现二叉树的创建,前序中序后序遍历(附完整代码)

    C++用类实现二叉树的创建,前序中序后序遍历(附完整代码) 前序.中序.后序遍历 直接上代码 前序.中序.后序遍历 二叉树的遍历分为前序遍历,中序遍历和后序遍历三种遍历方法.前序遍历的顺序为" ...

最新文章

  1. 71 Zabbix自定义触发器
  2. ***测试之情报收集
  3. python 字符串不区分大小写_还在吐槽文本字符串难以处理,Python的这个绝活你还不知道
  4. Myeclipse下使用Maven搭建spring boot项目(第二篇)
  5. logistic regression 逻辑回归
  6. 一周玩转示波器(六)
  7. mysql(基础案例篇)
  8. vsocde vue snippet 设置
  9. 北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
  10. java计算机毕业设计医院远程诊断系统源程序+mysql+系统+lw文档+远程调试
  11. 秋招Android常见笔试题合集--Binrry(冰蕊)
  12. bootstrap实战--微金所项目(轮播图1)
  13. R语言怎么比较两个模型C指数,手把手教你用R语言评价临床预测模型,一文就够(附代码)...
  14. 6GK5116-0BA00-2AB2的技术参数说明
  15. vscode开启LiveReload出错
  16. 三分钟黑掉阿里内网?他正在做的事将彻底改变现有商业模式!
  17. 留学生福利!超好用免费英文论文润色软件Wordvice AI上线啦
  18. 拼多多虚拟类目商品中有哪些是禁售品
  19. android gdx 放进布局,Android --- libgdx android 学习初步(环境搭建及测试)
  20. java面试题之equals和==的区别

热门文章

  1. LiteSeg: 一种用于语义分割的轻量级ConvNet
  2. React 项目 -ES6 语法类的继承 (10)
  3. ecplise 安装subclipse
  4. HashMap和LinkedHashMap的区别
  5. LeetCode 845. 数组中的最长山脉
  6. Linux 服务器更换主板后,网卡识别失败的处理方法
  7. 在线作图|你不知道的绘制带聚类树的堆叠柱状图的方法
  8. 港大徐爱民组研究助理招聘-内分泌代谢方向
  9. MPB:林科院袁志林组-​栎类外生菌根形态学特征描述
  10. Microbiome:根系分泌物驱动土壤记忆抵御植物病原菌(作者解读)