二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java)
public class Traverse { /******************一二进制树的定义**************************/
private final int MAX_SIZE = 10;
//链式存储
public static class BinaryTreeNode
{
int mValue;
BinaryTreeNode mLeft;
BinaryTreeNode mRight; public BinaryTreeNode(int mValue) {
this.mValue = mValue;
}
} //顺序存储
class BinaryTreeNode2
{
int[] data = new int[MAX_SIZE];
int length;
} //用以实现兴许遍历的辅助结构
private class HelpNode
{
BinaryTreeNode treeNode;
boolean isFirst;
} /******************递归实现***************************/
//先序遍历
public int PreOrderTreeWalk(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
visitNode(pNode);
PreOrderTreeWalk(pNode.mLeft);
PreOrderTreeWalk(pNode.mRight);
return 1;
} //中序遍历
public int InOrderTreeWalk(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
InOrderTreeWalk(pNode.mLeft);
visitNode(pNode);
InOrderTreeWalk(pNode.mRight);
return 1;
} //后序遍历
public int PostOrderTreeWalk(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
PostOrderTreeWalk(pNode.mLeft);
PostOrderTreeWalk(pNode.mRight);
visitNode(pNode);
return 1;
} /*****************非递归实现***********************/
//先序遍历
public int PreOrderTraverse(BinaryTreeNode pNode)
{
Stack<BinaryTreeNode> stack = new Stack<>();
if(pNode == null)
return 0; while(!stack.isEmpty()||pNode != null)
{
while(pNode != null)
{
//先訪问
visitNode(pNode);
stack.push(pNode);
//遍历左节点
pNode = pNode.mLeft;
}
//返回顶层元素
pNode = stack.peek();
stack.pop();
//遍历右节点
pNode = pNode.mRight;
}
return 1;
} //先序遍历实现方法二
public int PreOrderTraverse2(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
Stack<BinaryTreeNode> stack = new Stack<>();
stack.push(pNode); while(!stack.isEmpty())
{
pNode = stack.pop();
visitNode(pNode); if(pNode.mRight != null)
stack.push(pNode.mRight);
if(pNode.mLeft != null)
stack.push(pNode.mLeft);
}
return 1;
} //中序遍历
public int InOrderTraverse(BinaryTreeNode pNode)
{
Stack<BinaryTreeNode> stack = new Stack<>();
if(pNode == null)
return 0; while(!stack.isEmpty()||pNode != null)
{
while(pNode!=null)
{
stack.push(pNode);
pNode = pNode.mLeft;
}
pNode = stack.pop();
visitNode(pNode);
pNode = pNode.mRight;
}
return 1;
} //后序遍历,用一个标记标记右子树是否訪问过
/*
* 第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,
* 此时该结点出如今栈顶。可是此时不能将其出栈并訪问。因此其右孩子还为被訪问。 所以接下来依照同样
* 的规则对其右子树进行同样的处理。当訪问完其右孩子时。该结点又出如今栈顶,此时能够将其出栈并訪
* 问。这样就保证了正确的訪问顺序。能够看出。在这个过程中。每个结点都两次出如今栈顶,仅仅有在第二
* 次出如今栈顶时,才干訪问它。 因此须要多设置一个变量标识该结点是否是第一次出如今栈顶。
* */
public int PostOrderTraverse(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
Stack<HelpNode> stack = new Stack<>();
HelpNode helpNode;
while(!stack.isEmpty() || pNode != null)
{
//一直循环至最左节点
while(pNode != null)
{
HelpNode temp = new HelpNode();
temp.treeNode = pNode;
temp.isFirst = true;
stack.push(temp);
pNode = pNode.mLeft;
} if(!stack.isEmpty())
{
helpNode = stack.pop(); if(helpNode.isFirst)//表示第一次,即每个要被訪问的根节点要被push两次
{
helpNode.isFirst = false;
stack.push(helpNode);
pNode = helpNode.treeNode.mRight;//右节点的是否有效则移至循环的開始出进行推断
}
else
{
visitNode(helpNode.treeNode);
pNode = null;
}
}
}
return 1;
} //后序遍历实现方法二:双栈法
public int PostOrderTraverse2(BinaryTreeNode pNode)
{
if(pNode == null)
return 0;
Stack<BinaryTreeNode> stack1 = new Stack<>();
Stack<BinaryTreeNode> stack2 = new Stack<>();//辅助栈
//存入根节点,初始化
stack1.push(pNode);
//stack1弹出的元素,压入stack2,在将该元素的左右节点压入stack1
while(!stack1.isEmpty())
{
pNode = stack1.pop();
stack2.push(pNode);
if(pNode.mLeft != null)
{
stack1.push(pNode.mLeft);
}
if(pNode.mRight != null)
{
stack1.push(pNode.mRight);
}
} //stack弹出的即是后序遍历的顺序
while(!stack2.isEmpty())
{
visitNode(stack2.pop());
}
return 1;
} //后序遍历实现方法三
/*
* 另外一种思路:要保证根结点在左孩子和右孩子訪问之后才干訪问,因此对于任一结点P,先将其入栈。
* 假设P不存在左孩子和右孩子,则能够直接訪问它。或者P存在左孩子或者右孩子,可是其左孩子和右
* 孩子都已被訪问过了。则同样能够直接訪问该结点。若非上述两种情况。则将P的右孩子和左孩子依次
* 入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被訪问,左孩子和右孩子都在根结点
* 前面被訪问。
* */
//后序遍历实现方法二:双栈法
public int PostOrderTraverse3(BinaryTreeNode pNode)
{
if(pNode == null)
return 0; BinaryTreeNode preVisitedNode = null;
Stack<BinaryTreeNode> stack = new Stack<>();
stack.push(pNode); while(!stack.isEmpty())
{
pNode = stack.peek();
if((pNode.mLeft == null && pNode.mLeft == null)//左右子树均为空的情况,即叶子节点
||(preVisitedNode != null &&
(preVisitedNode == pNode.mLeft || preVisitedNode == pNode.mRight)))//左右子树已经被訪问的情况
{
visitNode(pNode);
preVisitedNode = stack.pop();
}
else
{
if(pNode.mRight != null)
stack.push(pNode.mRight);//注意push的顺序,先訪问右子树
if(pNode.mLeft != null)
stack.push(pNode.mLeft);
}
} return 1;
} /*********辅助函数**********/
//訪问节点数据
private void visitNode(BinaryTreeNode treeNode)
{
System.out.print(treeNode.mValue);
System.out.print("、");
} public static void main(String[] args)
{
/************************构造測试二叉树链表组***********************/
int[] data = {1,2,3,4,5,6,7,8,9,10};
BinaryTreeNode[] treeNodes = new BinaryTreeNode[data.length]; for(int i = 0; i < data.length; i++)
{
treeNodes[i] = new BinaryTreeNode(data[i]);
} for(int i = 0; i < (data.length/2); i ++)
{
treeNodes[i].mLeft = treeNodes[(i + 1)*2 - 1]; if(((i + 1) *2) < data.length)
{
treeNodes[i].mRight = treeNodes[(i + 1)*2];
}
}
Traverse traverse = new Traverse();
BinaryTreeNode root = treeNodes[0];
System.out.print("先序遍历递归: ");
traverse.PreOrderTreeWalk(root);
System.out.println(); System.out.print("先序遍历非递归一:");
traverse.PreOrderTraverse(root);
System.out.println(); System.out.print("先序遍历非递归二:");
traverse.PreOrderTraverse2(root);
System.out.println(); System.out.print("中序遍历递归: ");
traverse.InOrderTreeWalk(root);
System.out.println(); System.out.print("中序遍历递归: ");
traverse.InOrderTraverse(root);
System.out.println(); System.out.print("后序遍历递归: ");
traverse.PostOrderTreeWalk(root);
System.out.println(); System.out.print("后序遍历非递归一:");
traverse.PostOrderTraverse(root);
System.out.println(); System.out.print("后序遍历非递归二:");
traverse.PostOrderTraverse2(root);
System.out.println(); System.out.print("后序遍历非递归三:");
traverse.PostOrderTraverse3(root);
System.out.println();
/******************验证输出***********************/
// for(BinaryTreeNode treeNode : treeNodes)
// {
// System.out.print("根节点");
// System.out.println(treeNode.mValue);
// System.out.print("左节点");
// if(treeNode.mLeft != null)
// {
// System.out.println(treeNode.mLeft.mValue);
// }
// else
// {
// System.out.println("null");
// }
//
// System.out.print("右节点");
// if(treeNode.mRight != null)
// {
// System.out.println(treeNode.mRight.mValue);
// }
// else
// {
// System.out.println("null");
// }
// System.out.println();
// }
} }
版权声明:本文博主原创文章。博客,未经同意不得转载。
二叉树3种递归和非递归遍历(Java)的更多相关文章
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...
- C实现二叉树(模块化集成,遍历的递归与非递归实现)
C实现二叉树模块化集成 实验源码介绍(源代码的总体介绍):header.h : 头文件链栈,循环队列,二叉树的结构声明和相关函数的声明.LinkStack.c : 链栈的相关操作函数定义.Queue. ...
- JAVA递归、非递归遍历二叉树(转)
原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...
- 二叉树前中后/层次遍历的递归与非递归形式(c++)
/* 二叉树前中后/层次遍历的递归与非递归形式 */ //*************** void preOrder1(BinaryTreeNode* pRoot) { if(pRoot==NULL) ...
- 二叉树之AVL树的平衡实现(递归与非递归)
这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八 ...
- 数据结构-树以及深度、广度优先遍历(递归和非递归,python实现)
前面我们介绍了队列.堆栈.链表,你亲自动手实践了吗?今天我们来到了树的部分,树在数据结构中是非常重要的一部分,树的应用有很多很多,树的种类也有很多很多,今天我们就先来创建一个普通的树.其他各种各样的树 ...
- java扫描文件夹下面的所有文件(递归与非递归实现)
java中扫描指定文件夹下面的所有文件扫描一个文件夹下面的所有文件,因为文件夹的层数没有限制可能多达几十层几百层,通常会采用两种方式来遍历指定文件夹下面的所有文件.递归方式非递归方式(采用队列或者栈实 ...
- 回溯算法 DFS深度优先搜索 (递归与非递归实现)
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
- C语言实现 二分查找数组中的Key值(递归和非递归)
基本问题:使用二分查找的方式,对数组内的值进行匹配,如果成功,返回其下标,否则返回 -1.请使用递归和非递归两种方法说明. 非递归代码如下: #include <stdio.h> int ...
随机推荐
- Linux系统管理员必备的监控工具(88款)
随着互联网行业的不断发展,各种监控工具多得不可胜数.这里列出网上最全的监控工具.让你可以拥有超过80种方式来管理你的机器.在本文中,我们主要包括以下方面: 命令行工具 网络相关内容 系统相关的监控工具 ...
- JAVA中IO和NIO的详解分析,内容来自网络和自己总结
用一个例子来阐释: 一辆客车上有10个乘客,他们的目的地各不相同,当没有售票员的时候,司机就需要不断的询问每一站是否有乘客需要下车,需要则停下,不需要则继续开车,这种就是阻塞的方式. 当有售票员的时候 ...
- web服务器配置方法
Web服务器概述 Web服务器又称为WWW服务器,它是放置一般网站的服务器.一台Web服务器上可以建立多个网站,各网站的拥有者只需要把做好的网页和相关文件放置在Web服务器的网站中,其它用户就可以用浏 ...
- 八皇后问题详细分析与解答(递归法解答,c#语言描述)
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或 ...
- Core Data 和 sqlite3的性能对比【图】3gs,iPhone4,4s,5的性能测试。
demo 和源码再此下载 :http://download.csdn.net/detail/hherima/5603797
- skynet源代码学习 - 从全局队列中弹出/压入一个消息队列过程
学习云风的skynet源代码,简单记录下. void skynet_globalmq_push(struct message_queue * queue) { struct global_queue ...
- MySQL多表查询之外键、表连接、子查询、索引
MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...
- DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...
- Company Story | Vistaprint
Company Story | Vistaprint Company Story A Gap in the Small Business Marketplace It’s rare that a hi ...
- 4.windows和Linux下创建oracleusername表空间,表,插入数据,用户管理表等操作
进入超级管理员,运行下面命令 Window下创建数据库.表空间,用户,插入数据等操作 -- 01 创建表空间 -- 注意表空间的路径 依据实际安装环境进行调整 CREATE TABLESPACE ts ...