原文链接:http://www.dubby.cn/detail.html?id=9056
定义树的节点类型(为节省篇幅省略了getter/setter):
public class TreeNode<T> {
private T value;
private TreeNode<T> left;
private TreeNode<T> right;
}
前序遍历
前序遍历Preorder Traversal (DLR),是二叉树遍历的一种,也叫做先根遍历、先序遍历、前序周游,可记做根左右。前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。
前序遍历结果:ABDECF
已知后序遍历和中序遍历,就能确定前序遍历。
递归
public List<T> travelWithRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
doTravelRecursion(tree, result);
return result;
}
private void doTravelRecursion(TreeNode<T> tree, List<T> result) {
if (tree == null)
return;
result.add(tree.getValue());
if (tree.getLeft() != null)
doTravelRecursion(tree.getLeft(), result);
if (tree.getRight() != null)
doTravelRecursion(tree.getRight(), result);
}
非递归
public List<T> travelWithoutRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
Stack<TreeNode<T>> stack = new Stack<>();
stack.push(tree);
while (!stack.empty()) {
TreeNode<T> node = stack.pop();
result.add(node.getValue());
if (node.getRight() != null) {
stack.push(node.getRight());
}
if (node.getLeft() != null) {
stack.push(node.getLeft());
}
}
return result;
}
中序遍历
中序遍历Inorder Traversal (LDR)是二叉树遍历的一种,也叫做中根遍历、中序周游。在二叉树中,先左后根再右。巧记:左根右。
中序遍历结果:DBEAFC
递归
public List<T> travelWithRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
doTravelRecursion(tree, result);
return result;
}
private void doTravelRecursion(TreeNode<T> tree, List<T> result) {
if (tree == null)
return;
if (tree.getLeft() != null)
doTravelRecursion(tree.getLeft(), result);
result.add(tree.getValue());
if (tree.getRight() != null)
doTravelRecursion(tree.getRight(), result);
}
非递归
public List<T> travelWithoutRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
Stack<TreeNode<T>> stack = new Stack<>();
TreeNode<T> node = tree;
while (!stack.empty() || node != null) {
while (node != null) {
stack.push(node);
node = node.getLeft();
}
if (!stack.empty()) {
node = stack.pop();
result.add(node.getValue());
node = node.getRight();
}
}
return result;
}
后序遍历
后序遍历Postorder Traversal (LRD)是二叉树遍历的一种,也叫做后根遍历、后序周游,可记做左右根。后序遍历有递归算法和非递归算法两种。在二叉树中,先左后右再根。巧记:左右根。
后序遍历结果:DEBFCA
已知前序遍历和中序遍历,就能确定后序遍历。
递归
public List<T> travelWithRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
doTravelRecursion(tree, result);
return result;
}
private void doTravelRecursion(TreeNode<T> tree, List<T> result) {
if (tree == null)
return;
if (tree.getLeft() != null)
doTravelRecursion(tree.getLeft(), result);
if (tree.getRight() != null)
doTravelRecursion(tree.getRight(), result);
result.add(tree.getValue());
}
非递归
public List<T> travelWithoutRecursion(TreeNode<T> tree) {
List<T> result = new ArrayList<>();
Stack<TreeNode<T>> stack = new Stack<>();
TreeNode<T> currentNode = tree;
TreeNode<T> lastNode = null;
while (currentNode != null) {
stack.push(currentNode);
currentNode = currentNode.getLeft();
}
while (!stack.empty()) {
currentNode = stack.pop();
//只有“当前节点”没有右孩子或者右孩子已经被访问过了,才可以访问“当前节点”
if (currentNode.getRight() == null || currentNode.getRight() == lastNode) {
result.add(currentNode.getValue());
lastNode = currentNode;
} else {
stack.push(currentNode);
currentNode = currentNode.getRight();
while (currentNode != null) {
stack.push(currentNode);
currentNode = currentNode.getLeft();
}
}
}
return result;
}
测试
public class Test {
public static void main(String[] args) {
TreeNode<String> root = prepareData();
PreOrder<String> preOrder = new PreOrder<>();
InOrder<String> inOrder = new InOrder<>();
PostOrder<String> postOrder = new PostOrder<>();
System.out.println("先序遍历\t\t" + String.join(", ", preOrder.travelWithoutRecursion(root)));
System.out.println("先序遍历\t\t" + String.join(", ", preOrder.travelWithRecursion(root)));
System.out.println();
System.out.println("中序遍历\t\t" + String.join(", ", inOrder.travelWithoutRecursion(root)));
System.out.println("中序遍历\t\t" + String.join(", ", inOrder.travelWithRecursion(root)));
System.out.println();
System.out.println("后序遍历\t\t" + String.join(", ", postOrder.travelWithoutRecursion(root)));
System.out.println("后序遍历\t\t" + String.join(", ", postOrder.travelWithRecursion(root)));
System.out.println();
}
/**
* 1
* 2 3
* 4 5 6 7
*/
private static TreeNode<String> prepareData() {
TreeNode<String> root = new TreeNode<>();
root.setValue("1");
TreeNode<String> node1 = new TreeNode<>();
node1.setValue("2");
root.setLeft(node1);
TreeNode<String> node1_1 = new TreeNode<>();
node1_1.setValue("4");
node1.setLeft(node1_1);
TreeNode<String> node1_2 = new TreeNode<>();
node1_2.setValue("5");
node1.setRight(node1_2);
TreeNode<String> node2 = new TreeNode<>();
node2.setValue("3");
root.setRight(node2);
TreeNode<String> node2_1 = new TreeNode<>();
node2_1.setValue("6");
node2.setLeft(node2_1);
TreeNode<String> node2_2 = new TreeNode<>();
node2_2.setValue("7");
node2.setRight(node2_2);
return root;
}
}
结果:
先序遍历 1, 2, 4, 5, 3, 6, 7
先序遍历 1, 2, 4, 5, 3, 6, 7
中序遍历 4, 2, 5, 1, 6, 3, 7
中序遍历 4, 2, 5, 1, 6, 3, 7
后序遍历 4, 5, 2, 6, 7, 3, 1
后序遍历 4, 5, 2, 6, 7, 3, 1
源代码地址:https://github.com/dubby1994/tree-traversal