Java创建二叉树及其遍历的递归和非递归实现

来源:互联网 发布:手机游戏网络加速器 编辑:程序博客网 时间:2024/05/29 08:36

    紧接上一篇,网上搜索了Java实现二叉树的方法及二叉树的遍历方法,参考:http://blog.csdn.net/skylinesky/article/details/6611442

    学习和调试后代码如下:

    测试数据(#表示节点为空):

   

    所建立二叉树如下:

   

    代码如下:

   

// 树的节点public class TreeNode {private TreeNode left;private TreeNode right;private String val;public TreeNode(){}public TreeNode(String val) {super();this.val = val;}public TreeNode(TreeNode left, TreeNode right, String val) {super();this.left = left;this.right = right;this.val = val;}public TreeNode getLeft() {return left;}public void setLeft(TreeNode left) {this.left = left;}public TreeNode getRight() {return right;}public void setRight(TreeNode right) {this.right = right;}public String getVal() {return val;}public void setVal(String val) {this.val = val;}}

    创建二叉树及其中序、先序、后序遍历的递归和非递归实现方法、层次遍历

import java.io.File;import java.io.FileNotFoundException;import java.util.Queue;import java.util.Scanner;import java.util.Stack;import java.util.concurrent.LinkedBlockingQueue;public class Tree {private TreeNode root;public Tree() {}public Tree(TreeNode root) {this.root = root;}// 创建二叉树public void buildTree() {Scanner scn = null;try {scn = new Scanner(new File("D:\\test\\input.txt"));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}root = createTree(root, scn);}// 先序遍历创建二叉树private TreeNode createTree(TreeNode root, Scanner scn) {String temp = scn.next();if (temp.trim().equals("#")) {return null;} else {root = new TreeNode(temp);root.setLeft(createTree(root.getLeft(), scn));root.setRight(createTree(root.getRight(), scn));return root;}}// 中序遍历(递归) —— 左、根、右public void inOrderTraverse() {inOrderTraverse(root);}public void inOrderTraverse(TreeNode root) {if (root != null) {inOrderTraverse(root.getLeft());System.out.print(root.getVal() + " ");inOrderTraverse(root.getRight());}}// 中序遍历(非递归)public void nrInorderTraverse() {Stack<TreeNode> stack = new Stack<TreeNode>();TreeNode node = root;while (node != null || !stack.isEmpty()) { // 右子树不为空,或者栈不为空while (node != null) { // 从根或右子树开始,把所有的左孩子的左孩子全部入栈,直到找到最里面的左孩子stack.push(node);node = node.getLeft();}node = stack.pop(); // 出栈左孩子或者根节点System.out.print(node.getVal() + " ");node = node.getRight(); // 遍历之后,处理右子树内容。循环遍历右子树的左孩子等等}}// 先序遍历(递归) —— 根、左、右public void preOrderTraverse() {preOrderTraverse(root);}public void preOrderTraverse(TreeNode root) {if (root != null) {System.out.print(root.getVal() + " ");preOrderTraverse(root.getLeft());preOrderTraverse(root.getRight());}}// 先序遍历(非递归)public void nrPreOrderTraverse() {Stack<TreeNode> stack = new Stack<TreeNode>();TreeNode node = root;while (node != null || !stack.isEmpty()) { // 右子树不为空,或者栈不为空while (node != null) {System.out.print(node.getVal() + " "); // 遍历根节点和左子树的一系列的“根”,并将它们全部入栈stack.push(node);node = node.getLeft();}node = stack.pop(); // 弹出此时最里面的左子树根节点,判断其右子树情况node = node.getRight(); // 处理右子树情况}}// 后序遍历(递归) —— 左、右、根public void postOrderTraverse() {postOrderTraverse(root);}public void postOrderTraverse(TreeNode root) {if (root != null) {postOrderTraverse(root.getLeft());postOrderTraverse(root.getRight());System.out.print(root.getVal() + " ");}}// 后序遍历(非递归)public void nrPostOrderTraverse() {Stack<TreeNode> stack = new Stack<TreeNode>();TreeNode node = root;TreeNode preNode = null; // 表示最近一次访问的节点while (node != null || !stack.isEmpty()) { // 右子树不为空,或者栈不为空(其子树已经处理过)while (node != null) { // 将根节点和左子树的根节点入栈,直到左子树为空stack.push(node);node = node.getLeft();}node = stack.peek(); // stack.peek()查找栈顶对象,但不移除它 查看栈顶元素if (node.getRight() == null || node.getRight() == preNode) { // 该节点的右子树为空,或者其右子树已经被访问过System.out.print(node.getVal() + " "); // 访问该节点node = stack.pop();preNode = node;node = null; // 将node置为空,用于判断栈中的下一元素} else {node = node.getRight();}}}// 按层次遍历public void levelTraverse() {levelTraverse(root);}public void levelTraverse(TreeNode root) {Queue<TreeNode> queue = new LinkedBlockingQueue<TreeNode>(); // Queue为接口queue.add(root);while (!queue.isEmpty()) {TreeNode temp = queue.poll(); // queue.poll()获取并移除队头元素if (temp != null) {System.out.print(temp.getVal() + " ");if (temp.getLeft() != null) {queue.add(temp.getLeft());}if (temp.getRight() != null) {queue.add(temp.getRight());}}}}}

    注意:各种非递归方式的实现是借助栈或者队列来实现的,利用了它们的进出的特点,关于非递归的实现,可以从分析具体的遍历来得到思路。

    中序遍历和先序遍历的非递归方式有点类似,不同的地方在于,什么时候打印“根节点”。

    后序遍历,需要好好理解遍历节点操作(使用stack.peek方法,还有参数preNode)

    测试代码:

public class BinaryTreeTest {public static void main(String[] args) {Tree tree = new Tree();tree.buildTree();System.out.println("中序遍历");tree.inOrderTraverse();System.out.println("\n中序遍历(非递归)");tree.nrInorderTraverse();System.out.println("\n先序遍历");tree.preOrderTraverse();System.out.println("\n先序遍历(非递归)");tree.nrPreOrderTraverse();System.out.println("\n后序遍历");tree.postOrderTraverse();System.out.println("\n后序遍历(非递归)");tree.nrPostOrderTraverse();System.out.println("\n层次遍历");tree.levelTraverse();}}

    代码运行结果:

   

0 0