大话数据结构(七)——二叉树创建与遍历(递归、非递归)的java实现
2017-05-30 11:05
417 查看
什么是二叉树呢?二叉树是n(n>=0)个结点的有限组合,该集合或者为空集,或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。二叉树的具体结构如下图所示:
二叉树的遍历这里介绍三种方法:前序遍历,中序遍历和后序遍历。
前序遍历:前序遍历的规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再遍历右子树。若前序遍 历上图中的树,则遍历顺序为:ABDECFG
中序遍历:中序遍历的规则是若二叉树为空,则空操作返回,否则根结点开始(但并不是先访问根结点),中序遍布根结点的左子 树,然后是访问根结点,最后遍历右子树。若中序遍历上图中的树,则遍历顺序为:DBEAFCG
后序遍历:后序遍历的规则是若二叉树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根 结点。若后序遍历上图中的树,则遍历顺序为:DEBFGCA
下面的程序实现了创建一棵二叉树,并使用了递归和非递归的方法对这个二叉树进行了前序遍历,中序遍历和后序遍历。
二叉树创建和遍历的实现方法
package BinaryTree;
import java.util.Stack;
/**
* Created by jiangxs on 17-5-29.
*/
public class BinaryTree {
//创建二叉树的结点
public class TreeNode<T>{
private T data;//结点数据
private TreeNode leftChild;//左孩子指针
private TreeNode rightChild;//右孩子指针
//空构造器
public TreeNode(){}
//含结点数据的构造器
public TreeNode(T data){
this.data = data;
}
//新结点含结点数据并以leftChild结点为左孩子,rightChild结点为右孩子
public TreeNode(T data,TreeNode leftChild,TreeNode rightChild){
this(data);
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public T getData(){
return data;
}
public void setData(T data){
this.data = data;
}
public TreeNode getLeftChild(){
return leftChild;
}
public void setLeftChild(TreeNode leftChild){
this.leftChild = leftChild;
}
public TreeNode getRightChild(){
return rightChild;
}
public void setRightChild(TreeNode rightChild){
this.rightChild = rightChild;
}
}
/**
* 创建一棵二叉树
* A
* B C
* D E F G
*/
public TreeNode creatBinTree(){
//初始化各个结点,并对各个结点关联各自的左右孩子
TreeNode rootLeftLeft = new TreeNode("D",null,null);
TreeNode rootLeftRight = new TreeNode("E",null,null);
TreeNode rootRightLeft = new TreeNode("F",null,null);
TreeNode rootRightRight = new TreeNode("G",null,null);
TreeNode rootLeft = new TreeNode("B",rootLeftLeft,rootLeftRight);
TreeNode rootRight = new TreeNode("C",rootRightLeft,rootRightRight);
TreeNode root = new TreeNode("A",rootLeft,rootRight);
return root;
}
/**
* 前序遍历法
* 递归版本
*/
public void recursePreOrderTraverse(TreeNode root){
if (root == null)
return;
System.out.println("当前结点数据: "+root.getData());
recursePreOrderTraverse(root.leftChild);
recursePreOrderTraverse(root.rightChild);
}
/**
* 前序遍历法
* 非递归版本
*/
public void preOrderTraverse(TreeNode root){
//若根结点为空则直接结束
if (root == null)
return;
//初始化用于存放结点顺序的栈结构
Stack<TreeNode> stack = new Stack<TreeNode>();
//首先将根结点放入栈中一遍最初就弹出
stack.add(root);
while (!stack.isEmpty()){
//取出栈顶结点,并将其暂时存入temp
TreeNode temp = stack.pop();
System.out.println("当前结点数据: "+temp.getData());
//栈是后进先出结构,故先存入右子结点,再存入左子结点
if (temp.rightChild != null)
stack.push(temp.getRightChild());
if (temp.leftChild != null)
stack.push(temp.getLeftChild());
}
}
/**
* 中序遍历法
* 递归版本
*/
public void recurseInOrderTraverse(TreeNode root){
if (root == null)
return;
recurseInOrderTraverse(root.leftChild);
System.out.println("当前结点数据: "+root.getData());
recurseInOrderTraverse(root.rightChild);
}
/**
* 中序遍历法
* 非递归版本
*/
public void inOrderTranverse(TreeNode root){
if (root == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
//依靠root!=null进入循环
while (!stack.isEmpty() || root != null){
//如果根结点存在就将根节点压栈
if (root != null){
stack.push(root);
//更新根结点
root = root.leftChild;
}
else {
//如果根结点不存在就弹栈,使用temp保存弹栈元素
TreeNode temp = stack.pop();
//打印弹栈元素
System.out.println("当前结点数据: "+temp.getData());
//更新根结点
root = temp.rightChild;
}
}
}
/**
* 后序遍历法
* 递归版本
*/
public void recursePostOrderTraverse(TreeNode root){
if (root == null)
return;
recursePostOrderTraverse(root.leftChild);
recursePostOrderTraverse(root.rightChild);
System.out.println("当前结点数据: "+root.getData());
}
/**
* 后序遍历法
* 递归版本
*/
public void postOrderTraverse(TreeNode root){
if (root == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
//初始化打印过的结点
TreeNode printedNode = null;
while (!stack.isEmpty()){
//获取栈顶结点
root = stack.peek();
//如果一个结点的左子结点存在且该结点的左右子节点均未被打印,则说明这个结点是新的,将其压入栈
if (root.leftChild != null && printedNode != root.getLeftChild() && printedNode != root.getRightChild()){
stack.push(root.getLeftChild());
}
//如果一个结点左子结点为空或者已被打印,而且该结点的右子结点存在且未被打印,则将其压入栈中
else if (root.rightChild != null && printedNode != root.getRightChild()){
stack.push(root.getRightChild());
}
//若以上两个均不满足,说明该结点不能存在左右结点或者该结点的子结点均已被打印,则将该结点弹出并打印
else {
System.out.println("当前结点数据: "+stack.pop().getData());
//更新已被打印过的结点
printedNode = root;
}
}
}
}
测试代码
package BinaryTree;
/**
* Created by jiangxs on 17-5-29.
*/
public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
BinaryTree.TreeNode root = bt.creatBinTree();
System.out.println("----------递归前序遍历----------");
bt.recursePreOrderTraverse(root);
System.out.println("----------非递归前序遍历--------");
bt.preOrderTraverse(root);
System.out.println("----------递归中序遍历----------");
bt.recurseInOrderTraverse(root);
System.out.println("----------非递归中序遍历--------");
bt.inOrderTranverse(root);
System.out.println("----------递归后序遍历----------");
bt.recursePostOrderTraverse(root);
System.out.println("----------非递归后序遍历--------");
bt.postOrderTraverse(root);
}
}
测试结果
--
b36d
--------递归前序遍历----------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------非递归前序遍历--------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------递归中序遍历----------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------非递归中序遍历--------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------递归后序遍历----------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A
----------非递归后序遍历--------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A
Process finished with exit code 0
参考:《大话数据结构》
二叉树的遍历这里介绍三种方法:前序遍历,中序遍历和后序遍历。
前序遍历:前序遍历的规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再遍历右子树。若前序遍 历上图中的树,则遍历顺序为:ABDECFG
中序遍历:中序遍历的规则是若二叉树为空,则空操作返回,否则根结点开始(但并不是先访问根结点),中序遍布根结点的左子 树,然后是访问根结点,最后遍历右子树。若中序遍历上图中的树,则遍历顺序为:DBEAFCG
后序遍历:后序遍历的规则是若二叉树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根 结点。若后序遍历上图中的树,则遍历顺序为:DEBFGCA
下面的程序实现了创建一棵二叉树,并使用了递归和非递归的方法对这个二叉树进行了前序遍历,中序遍历和后序遍历。
二叉树创建和遍历的实现方法
package BinaryTree;
import java.util.Stack;
/**
* Created by jiangxs on 17-5-29.
*/
public class BinaryTree {
//创建二叉树的结点
public class TreeNode<T>{
private T data;//结点数据
private TreeNode leftChild;//左孩子指针
private TreeNode rightChild;//右孩子指针
//空构造器
public TreeNode(){}
//含结点数据的构造器
public TreeNode(T data){
this.data = data;
}
//新结点含结点数据并以leftChild结点为左孩子,rightChild结点为右孩子
public TreeNode(T data,TreeNode leftChild,TreeNode rightChild){
this(data);
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public T getData(){
return data;
}
public void setData(T data){
this.data = data;
}
public TreeNode getLeftChild(){
return leftChild;
}
public void setLeftChild(TreeNode leftChild){
this.leftChild = leftChild;
}
public TreeNode getRightChild(){
return rightChild;
}
public void setRightChild(TreeNode rightChild){
this.rightChild = rightChild;
}
}
/**
* 创建一棵二叉树
* A
* B C
* D E F G
*/
public TreeNode creatBinTree(){
//初始化各个结点,并对各个结点关联各自的左右孩子
TreeNode rootLeftLeft = new TreeNode("D",null,null);
TreeNode rootLeftRight = new TreeNode("E",null,null);
TreeNode rootRightLeft = new TreeNode("F",null,null);
TreeNode rootRightRight = new TreeNode("G",null,null);
TreeNode rootLeft = new TreeNode("B",rootLeftLeft,rootLeftRight);
TreeNode rootRight = new TreeNode("C",rootRightLeft,rootRightRight);
TreeNode root = new TreeNode("A",rootLeft,rootRight);
return root;
}
/**
* 前序遍历法
* 递归版本
*/
public void recursePreOrderTraverse(TreeNode root){
if (root == null)
return;
System.out.println("当前结点数据: "+root.getData());
recursePreOrderTraverse(root.leftChild);
recursePreOrderTraverse(root.rightChild);
}
/**
* 前序遍历法
* 非递归版本
*/
public void preOrderTraverse(TreeNode root){
//若根结点为空则直接结束
if (root == null)
return;
//初始化用于存放结点顺序的栈结构
Stack<TreeNode> stack = new Stack<TreeNode>();
//首先将根结点放入栈中一遍最初就弹出
stack.add(root);
while (!stack.isEmpty()){
//取出栈顶结点,并将其暂时存入temp
TreeNode temp = stack.pop();
System.out.println("当前结点数据: "+temp.getData());
//栈是后进先出结构,故先存入右子结点,再存入左子结点
if (temp.rightChild != null)
stack.push(temp.getRightChild());
if (temp.leftChild != null)
stack.push(temp.getLeftChild());
}
}
/**
* 中序遍历法
* 递归版本
*/
public void recurseInOrderTraverse(TreeNode root){
if (root == null)
return;
recurseInOrderTraverse(root.leftChild);
System.out.println("当前结点数据: "+root.getData());
recurseInOrderTraverse(root.rightChild);
}
/**
* 中序遍历法
* 非递归版本
*/
public void inOrderTranverse(TreeNode root){
if (root == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
//依靠root!=null进入循环
while (!stack.isEmpty() || root != null){
//如果根结点存在就将根节点压栈
if (root != null){
stack.push(root);
//更新根结点
root = root.leftChild;
}
else {
//如果根结点不存在就弹栈,使用temp保存弹栈元素
TreeNode temp = stack.pop();
//打印弹栈元素
System.out.println("当前结点数据: "+temp.getData());
//更新根结点
root = temp.rightChild;
}
}
}
/**
* 后序遍历法
* 递归版本
*/
public void recursePostOrderTraverse(TreeNode root){
if (root == null)
return;
recursePostOrderTraverse(root.leftChild);
recursePostOrderTraverse(root.rightChild);
System.out.println("当前结点数据: "+root.getData());
}
/**
* 后序遍历法
* 递归版本
*/
public void postOrderTraverse(TreeNode root){
if (root == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
//初始化打印过的结点
TreeNode printedNode = null;
while (!stack.isEmpty()){
//获取栈顶结点
root = stack.peek();
//如果一个结点的左子结点存在且该结点的左右子节点均未被打印,则说明这个结点是新的,将其压入栈
if (root.leftChild != null && printedNode != root.getLeftChild() && printedNode != root.getRightChild()){
stack.push(root.getLeftChild());
}
//如果一个结点左子结点为空或者已被打印,而且该结点的右子结点存在且未被打印,则将其压入栈中
else if (root.rightChild != null && printedNode != root.getRightChild()){
stack.push(root.getRightChild());
}
//若以上两个均不满足,说明该结点不能存在左右结点或者该结点的子结点均已被打印,则将该结点弹出并打印
else {
System.out.println("当前结点数据: "+stack.pop().getData());
//更新已被打印过的结点
printedNode = root;
}
}
}
}
测试代码
package BinaryTree;
/**
* Created by jiangxs on 17-5-29.
*/
public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
BinaryTree.TreeNode root = bt.creatBinTree();
System.out.println("----------递归前序遍历----------");
bt.recursePreOrderTraverse(root);
System.out.println("----------非递归前序遍历--------");
bt.preOrderTraverse(root);
System.out.println("----------递归中序遍历----------");
bt.recurseInOrderTraverse(root);
System.out.println("----------非递归中序遍历--------");
bt.inOrderTranverse(root);
System.out.println("----------递归后序遍历----------");
bt.recursePostOrderTraverse(root);
System.out.println("----------非递归后序遍历--------");
bt.postOrderTraverse(root);
}
}
测试结果
--
b36d
--------递归前序遍历----------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------非递归前序遍历--------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------递归中序遍历----------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------非递归中序遍历--------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------递归后序遍历----------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A
----------非递归后序遍历--------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A
Process finished with exit code 0
参考:《大话数据结构》
相关文章推荐
- Java创建二叉树及其遍历的递归和非递归实现
- java实现二叉树的创建及三种递归遍历
- 【Java】二叉树三种遍历的递归实现
- 数据结构(二叉树系列)先序创建三种遍历和求深度(递归实现)
- java语言实现的二叉树的各种操作(包括递归与非递归遍历二叉树,求二叉树的高度,节点总数,叶子节点等)
- java实现二叉树的三种遍历算法(递归)
- 二叉树(一):二叉树的创建以及三种遍历方法的递归实现
- 算法:二叉树的先(根)序遍历、中(根)序遍历、后(根)序遍历(递归及压栈出栈实现的非递归方式)的java代码实现
- 我用Java实现的二叉树的遍历(递归和非递归)
- 二叉树的遍历 递归非递归 思路和 java实现
- 二叉树的遍历 递归非递归 思路和 java实现
- 二叉树的创建,遍历,查找,查找父节点,深度,大小等的递归实现
- 二叉树的创建及遍历--java实现
- JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)
- 算法:二叉树的先序遍历、中序遍历、后序遍历(递归及非递归方式)的java代码实现
- Java方式实现二叉树的前中后序遍历的递归及非递归算法
- 二叉树的遍历 递归非递归 思路和 java实现
- Java实现二叉树后序非递归遍历
- 二叉树的创建与先、中、后序遍历递归实现
- 二叉树创建、遍历的递归和非递归实现