二叉树前中后序遍历——迭代和栈方式实现
用递归实现三种遍历方式只需改变递归顺序就可以实现任一顺序的遍历。而使用栈方式,则不同情况需要进行不同的考虑。
首先,定义一个简单的二叉树节点的数据结构类:
class Node {
int val;
Node left;
Node right;
public Node(int val) {
this.val = val;
}
}
然后,初始化一个二叉树(这里是一个二叉查找树1,2,3,4,5,6,7)
//初始化一棵二叉树 Node node1 = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); Node node5 = new Node(5); Node node6 = new Node(6); Node node7 = new Node(7); node4.left = node2; node4.right = node6; node2.left = node1; node2.right = node3; node6.left = node5; node6.right = node7;
树的结构,一目了然。
前序遍历
/** * 前序遍历迭代方式 * 迭代方式很好理解,先根节点,再左,再右 */ static void preTraverIter(Node root) { if (root == null) return; System.out.print(root.val + " "); preTraverIter(root.left); preTraverIter(root.right); } /** * 前序遍历栈方式 * 每次输出根节点,在输出左节点和右节点。步骤如下: * 1、若栈非空输出根节点,并出栈 * 2、将右节点压栈(如果存在) * 3、将左节点压栈(如果存在) * 4、重复第1步直到栈空 */ static void preTraverStack(Node root) { Stack<Node> stack = new Stack<>(); stack.add(root); while (!stack.isEmpty()) { Node node = stack.pop(); if (node.right != null) stack.push(node.right); if (node.left != null) stack.push(node.left); System.out.print(node.val + " "); } }
中序遍历
/** * 中序遍历迭代方式 * 先调用左节点,再调用根节点,再调用右节点 */ static void inorderTraversalIter(Node root) { if (root == null) return; inorderTraversalIter(root.left); System.out.print(root.val + " "); inorderTraversalIter(root.right); } /** * 中序遍历栈方式 * 栈的中序遍历需要套两层循环,由于需要先输出左节点,必须向下查找直到左节点为空才能输出。 * 1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步 * 2、若栈非空,输出栈顶元素并出栈。判断刚出栈的元素的右节点是否存在,不存在重复第2步,存在则将右节点入栈,跳至第1步 */ static void inorderTraversalStack(Node root) { Stack<Node> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()) { while (stack.peek().left != null) { stack.push(stack.peek().left); } while (!stack.isEmpty()) { Node node = stack.pop(); System.out.print(node.val + " "); if (node.right != null) { stack.push(node.right); break; } } } }
后序遍历
/** * 后续遍历迭代方式 * 顺序左右中 */ static void postTraversalIter(Node root) { if (root == null) return; postTraversalIter(root.left); postTraversalIter(root.right); System.out.print(root.val + " "); } /** * 后续遍历栈方式 * 需要增加一个节点记录,用于记录上次出栈的节点 * 1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步(该过程和中序遍历一致) * 2、判断上一次出栈节点是否当前节点的右节点,或者当前节点是否存在右节点,满足任一条件,将当前节点输出,并出栈。否则将右节点压栈。跳至第1步 */ static void postTraversalStack(Node root) { Stack<Node> stack = new Stack<>(); stack.push(root); Node lastNode = null; while (!stack.isEmpty()) { while (stack.peek().left != null) { stack.push(stack.peek().left); } while (!stack.isEmpty()) { if (lastNode == stack.peek().right || stack.peek().right == null) { Node node = stack.pop(); System.out.print(node.val + " "); lastNode = node; } else if (stack.peek().right != null) { stack.push(stack.peek().right); break; } } } }
测试输出
System.out.print("前序遍历迭代方式:"); preTraverIter(node4); System.out.print("\n前序遍历栈方式:"); preTraverStack(node4); System.out.print("\n中序遍历迭代方式:"); inorderTraversalIter(node4); System.out.print("\n中序遍历栈方式:"); inorderTraversalStack(node4); System.out.print("\n后序遍历迭代方式:"); postTraversalIter(node4); System.out.print("\n后序遍历栈方式:"); postTraversalStack(node4);
输出:
前序遍历迭代方式:4 2 13 6 5 7
前序遍历栈方式:4 2 13 6 5 7
中序遍历迭代方式:1 2 34 5 6 7
中序遍历栈方式:1 2 34 5 6 7
后序遍历迭代方式:1 3 25 7 6 4
后序遍历栈方式:1 3 25 7 6 4
很显然,二叉查找树的中序遍历是有序的。
先序和后序,不能唯一确定二叉树
先序和中序,能唯一确定二叉树
后序和中序,能唯一确定二叉树
先序、中序相同时,二叉树没有左子树
后序、中序相同时,二叉树没有右子树
后序、先序相同时,只有一个根节点
复习一下。