package cn.alex.demo;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
/**
* 树的遍历方式 深度优先遍历:递归和非递归两种 广度优先遍历:
*
* @author AlexDiner
*
*/
public class PrintTree {
public static void main(String[] args) {
TreeNode tree = createTree();
// System.out.println("递归方式先序遍历:");
// ForeachTree.rePreTree(tree);
// System.out.println("非递归方式先序遍历:");
// ForeachTree.nRePreTree(tree);
// System.out.println("递归方式中序遍历:");
// ForeachTree.reInTree(tree);
// System.out.println("非递归方式中序遍历:");
// ForeachTree.nReInTree(tree);
// System.out.println("递归方式后序遍历:");
// ForeachTree.reEndTree(tree);
// System.out.println("非递归方式后序遍历:");
// ForeachTree.nReEndTree(tree);
System.out.println("广度优先遍历:");
ForeachTree.BFSTree(tree);
}
/**
* 创建一个用作测试的树
*
* @return
*/
public static TreeNode createTree() {
/*
* 示例:
* 1
* 2 3
* 4 5 6 7
* 8 9
*/
TreeNode root = new TreeNode(1);
TreeNode left1Tree = new TreeNode(2);
TreeNode left2Tree = new TreeNode(4);
TreeNode left3Tree = new TreeNode(8);
TreeNode left4Tree = new TreeNode(6);
TreeNode right1Tree = new TreeNode(5);
TreeNode right2Tree = new TreeNode(9);
TreeNode right3Tree = new TreeNode(3);
TreeNode right4Tree = new TreeNode(7);
left2Tree.leftNode = left3Tree;
right1Tree.rightNode = right2Tree;
left1Tree.leftNode = left2Tree;
left1Tree.rightNode = right1Tree;
right3Tree.leftNode = left4Tree;
right3Tree.rightNode = right4Tree;
root.leftNode = left1Tree;
root.rightNode = right3Tree;
return root;
}
}
class ForeachTree {
/**
* 先序遍历:根左右的顺序--递归方式
*
* @param tree
*/
public static void rePreTree(TreeNode tree) {
if (tree != null) {
System.out.println(tree.val);
rePreTree(tree.leftNode);
rePreTree(tree.rightNode);
}
}
/**
* 先序遍历:根左右的顺序--非递归方式
* 思路:
* 1. 获取当前节点,首先输出当前节点,然后将其两个节点压入栈中,然后利用栈的先进后出的特性,弹出节点并获取其子节点
* 2. 在此判断条件为当前节点不为空,若为空则直接结束本次循环然后进行下一次循环
* @param tree
*/
public static void nRePreTree(TreeNode tree) {
// 创建栈,由于深度遍历是
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(tree);
while (stack != null && !stack.isEmpty()) {
TreeNode te = stack.pop();
System.out.println(te.val);
List<TreeNode> trees = te.getChildren();
if(trees == null) continue;
for(TreeNode t:trees) {
if(t!=null) {
stack.push(t);
}
}
}
}
/**
* 中序遍历:左根右的顺序--递归方式
*
* @param tree
*/
public static void reInTree(TreeNode tree) {
if (tree != null) {
reInTree(tree.leftNode);
System.out.println(tree.val);
reInTree(tree.rightNode);
}
}
/**
* 中序遍历:左根右的顺序--非递归方式
* 思路:
* 1. 由于中序遍历方式为左根右,所以先判断当前节点是否有左子节点,若有的话将当前节点的左子节点置为空(防止下次遍历到重复判
* 断)再压入栈,然后将当前节点的左子节点压入栈,一次类推
* 2. 直到当前节点没有左子节点时,输出当前节点的值,然后判断是否有右子节点,若有的话则继续进行压栈操作(在此有一技巧之处在
* 于若该节点的左右子节点都没有的话,则不需要将当前节点压入栈--在第一次获取当前节点时已经将当前节点弹出了)
* 3. 注:只有在当前节点有左子节点时需要将当前节点压入栈,因为遍历顺序为左中右,所以在当前节点有左节点时,需要再进行回根节
* 点查找输出根节点的值,若当前节点没有左节点时,则不需要记录上一节点
* @param tree
*/
public static void nReInTree(TreeNode tree) {
// 创建栈,由于深度遍历是
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(tree);
while(stack != null && !stack.isEmpty()) {
TreeNode root = stack.pop();
if(root.leftNode != null) {
TreeNode left = root.leftNode;
root.leftNode = null;
stack.push(root);
stack.push(left);
}else {
System.out.println(root.val);
if(root.rightNode != null) {
TreeNode right = root.rightNode;
stack.push(right);
}
}
}
}
/**
* 后序遍历:左右根的顺序--递归方式
*
* @param tree
*/
public static void reEndTree(TreeNode tree) {
if (tree != null) {
reEndTree(tree.leftNode);
reEndTree(tree.rightNode);
System.out.println(tree.val);
}
}
/**
* 后序遍历:左右根的顺序--非递归方式
*
* @param tree
*/
public static void nReEndTree(TreeNode tree) {
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(tree);
while( stack != null && !stack.isEmpty()) {
TreeNode root = stack.pop();
if(root.leftNode != null) {
TreeNode left = root.leftNode;
root.leftNode = null;
stack.push(root);
stack.push(left);
}else if(root.rightNode != null) {
TreeNode right = root.rightNode;
root.rightNode = null;
stack.push(root);
stack.push(right);
}else {
System.out.println(root.val);
}
}
}
/**
* 广度优先遍历
*
* @param tree
*/
public static void BFSTree(TreeNode tree) {
Deque<TreeNode> queue = new ArrayDeque<TreeNode>();
queue.push(tree);
while (queue != null && !queue.isEmpty()) {
TreeNode root = queue.pop();
System.out.println(root.val);
if (root.leftNode != null) {
queue.add(root.leftNode);
}
if (root.rightNode != null) {
queue.add(root.rightNode);
}
}
}
}
class TreeNode {
int val;
public TreeNode(int val) {
this.val = val;
}
TreeNode leftNode;
TreeNode rightNode;
/**
* 获取该节点的所有左右子节点-先右后左
* 由于所有遍历方式都是从左向右的顺序,所以压入栈时需要先将右子节点压入,后将左子节点压入,
* 因此在此获取子节点时先添加右子节点,后添加左子节点
* @return
*/
public List<TreeNode> getChildren() {
List<TreeNode> list = new LinkedList<TreeNode>();
if (this.rightNode != null)
list.add(this.rightNode);
if (this.leftNode != null)
list.add(this.leftNode);
return list.size() == 0 ? null : list;
}
}
以上代码如有疑问,可以私聊笔者或留言给笔者,谢谢