今天分享下二叉树的前中序遍历的迭代实现。
我们都知道用递归来实现前中后序遍历是很简单的,非递归的实现则麻烦一些,我们先看看非递归的思路是什么。
定义TreeNode结构如下:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) {
val = x;
}
}
前序遍历
思路
前序遍历的顺序是根节点-左节点-右节点。之后我们需要一个栈,首先把根节点压入栈。
之后我们就开始循环弹出栈元素,然后打印该元素的值,之后判断如果该元素的右节点不为空,则将右节点压入栈,之后在判断该元素的左节点是否为空,如果不为空再将左节点压入栈。然后重复循环。
代码
public static void preorderTraversal(TreeNode root) {
Stack stack = new Stack<>();
//根节点入栈
stack.push(root);
while (!stack.isEmpty()) {
//弹出元素并打印
TreeNode node = stack.pop();
System.out.println(node.val);
//判断右节点是否为空
if (node.right != null) {
stack.push(node.right);
}
//判断左节点是否为空
if (node.left != null) {
stack.push(node.left);
}
}
}
中序遍历
思路
中序遍历则比前序麻烦一些,中序的顺序是左节点-根节点-右节点。
步骤一:我们将根节点和根节点的左节点压入栈,再去对根节点的左节点做同样的操作,直到把叶子结点压入栈。
步骤二:之后弹出元素并打印记录,之后判断如果该元素有右节点,则将右节点视为根节点,重复步骤1。
代码
public List inorderTraversal(TreeNode root) {
List r = new ArrayList<>();
Stack stack = new Stack<>();
//根节点和根节点的左节点入栈
TreeNode node = root;
while (node != null) {
stack.push(node);
node = node.left;
}
while (!stack.isEmpty()) {
//弹出元素
TreeNode popNode = stack.pop();
//记录元素值
r.add(popNode.val);
if (popNode.right != null) {
//如果元素的右节点不为空则视为根节点重复步骤一
TreeNode tmp = popNode.right;
while (tmp != null) {
stack.push(tmp);
tmp = tmp.left;
}
}
}
return r;
}
总结
对于二叉树的前中序遍历的非递归实现,我们都使用到了栈。递归的复杂度是O(logn),而迭代的复杂度是O(n)。但是我们在解决某些问题的时候,使用迭代比递归好,比如写一个方法,调用一次返回一个以前序遍历得到的元素,因为迭代可以记录迭代的位置,而递归则不好记录栈帧的状态。