前序遍历
- 思路:模仿递归实现的栈帧结构先把根节点打印出来,然后右左子树分别入栈(为啥是右左不是左右?因为出栈的时候要左子树在右子树之前打印,右左刚好可以满足),直到栈为空。
- 实现代码
public static void preTraverse(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.println(node);
if(node.right != null) {
stack.push(node.right);
}
if(node.left != null) {
stack.push(node.left);
}
}
}
中序遍历
- 思路:因为要首先打印左子树,所以在一个栈中先插入根节点,然后一直插入左子树,直到左子树为空,开始打印(入栈循环体)。这样栈顶元素一定是左节点,然后出栈打印,再将右子树按照之前的方法插入到栈中(打印循环体)
- 实现代码:
public static void midTraverse(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null ||!stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode node = stack.pop();
System.out.println(node);
cur = node.right;
}
后续遍历
- 思路:和中序遍历一样因为要先打印左子树所以入栈循环体不变,不同之处在于要先打印右子树,后打印根节点,打印根节点的前提是判断上次打印的节点是右子树还是左子树,如果是右子树直接打印,如果是左子树则需要进入右子树,之后在打印,因此我们定义一个前驱节点来记录上次打印的节点,如果这节点不等于右子树则需要进入右子树
- 实现代码:
public static void postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode pre = null;
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
if(node.right != null && node.right != pre) {
stack.push(node);
cur = node.right;
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
}else {
System.out.println(node);
pre = node;
}
}
}