二叉树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 ...
随机推荐
- vscode编写插件
vscode编写插件详细过程 前言 之前编写了一个vscode插件用vscode写博客和发布,然后有园友要求写一篇来介绍如何开发一个vscode扩展插件,或者说介绍开发这个插件的过程.然而文章还没有写 ...
- 引导加载程序:GRUB
计算机在启动的时候,首先由BIOS中的程序执行自检,自检通过后,就根据CMOS的配置找到第一个可启动磁盘的MBR中的Boot Loader程序(一般在启动盘的第一个物理扇区,占446字节),并把控制权 ...
- 将Ojective-C代码移植转换为Swift代码
相比于Objective-C,Swift语言更加简练.有时我们需要把原来写的一些Objective-C代码转换成Swift,下面总结了各种常见的情况. 1,构造函数的迁移 Objective-C为: ...
- Swift - 图像控件(UIImageView)的用法
1,使用图像控件显示图片 1 2 3 var imageView=UIImageView(image:UIImage(named:"icon")) imageView.frame= ...
- SetDlgItemText控件运行错误
SetDlgltem函数把一个WM_SETTEXT消息发送到指定的控件. 今天在测试一个小程序,发现使用SetDlgItemText控件编译没问题,但是运行就出错误. 语句为: time=CTime: ...
- 不显示系统错误对话框SetErrorMode(要学会搜索)
关闭程序时报dde server window错误有人碰到过吗,用的别人的一个OCX控件,把这个控件去掉就不会报这个错误 //不显示系统错误对话框 SetErrorMode(SEM_NOGPFAULT ...
- Threejs 的场景查看 - 几个交互事件库助你方便查看场景
Threejs 的场景查看 - 几个交互事件库助你方便查看场景 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致&q ...
- android 视频文件不能进行幻灯片的播放
packages\apps\Gallery2\src\com\android\gallery3d\app\SlideshowPage.java中: 1.加入: import com.android ...
- Virtualbox mouse move in and out and file share with windows
How to use Virstalbox to share files with Linux and Windows, and to move the mouse in and out Virtua ...
- 4.2、Libgdx每个模块概述
(原版的:http://www.libgdx.cn/topic/34/4-2-libgdx%E5%90%84%E4%B8%AA%E6%A8%A1%E5%9D%97%E6%A6%82%E8%A7%88) ...