递归/迭代遍历二叉树
(对应leetcode94(中序)、144(前序)、145(后序))
递归解法
前序遍历
public static void preOrderRecur(TreeNode head) {
if (head == null) {
return;
}
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
前序遍历结果是:ABDHKECFIGJ
中序遍历
public static void preOrderRecur(TreeNode head) {
if (head == null) {
return;
}
preOrderRecur(head.left);
System.out.print(head.value + " ");
preOrderRecur(head.right);
}
中序遍历结果是:HKDBEAIFCGJ
后序遍历
public static void postOrderRecur(TreeNode head) {
if (head == null) {
return;
}
postOrderRecur(head.left);
postOrderRecur(head.right);
System.out.print(head.value + " ");
}
后序遍历结果是:KHDEBIFJGCA
迭代解法
迭代与递归的区别:迭代使用的是循环结构,递归使用的是选择结构。递归能使程序的结构更清晰、更简洁、更容易让人理解,从而减少读懂代码的时间。但是大量的递归调用会建立函数的副本,会消耗大量的时间和内存。迭代则不需要反复调用函数和占用额外的内存。
迭代本质上是在模拟递归。编译器实际上是用栈来实现递归。递归有前行和退回阶段,在前行阶段,函数的局部变量、参数值以及返回地址被压入栈中。在退回阶段,数据被弹出,函数恢复被调用的状态。所以迭代的解法用栈来实现。
前序遍历
前序遍历先访问根节点,然后前序遍历左子树,再前序遍历右子树。
当用栈实现时,则先打印出根节点,然后先将右子树压入栈中再将左子树压入栈中,再进行打印。
public static void preOrderIteration(TreeNode head) {
if (head == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(head);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.print(node.value + " ");
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
代码详解
1、根节点压入栈中
Stack<TreeNode> stack = new Stack<>();
stack.push(head);
2、将根节点弹出并打印
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.print(node.value + " ");
3、分别将右节点、左节点压入栈中
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
4、以图中二叉树为例:根节点A首先打印,之后右节点C、左节点B分别压入栈中。由于栈非空,所以栈底元素B被弹出打印,所以node为节点B。接着将B节点的右孩子E、左孩子D压入栈中。栈非空,栈底元素D被弹出打印,以此类推。最终遍历结果为:ABDHKECFIGJ。
中序遍历
中序遍历实际上是从根节点开始一直寻找他的左孩子,直到某一结点没有左孩子则打印此节点,接着看此节点有没有右孩子,没有返回上一节点,有的话看他的右孩子有没有左孩子,没有的话打印右孩子,有的话继续向下寻找没有左孩子的节点。
public static void inOrderIteration(TreeNode head) {
if (head == null) {
return;
}
TreeNode cur = head;
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || cur != null) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode node = stack.pop();
System.out.print(node.value + " ");
if (node.right != null) {
cur = node.right;
}
}
}
代码详解
仍然以图片二叉树为例
首先将根节点A压入栈中,然后用while循环寻找没有左孩子的节点,途经的节点依次压入栈中,直到找到节点H,打印。因为节点H有右孩子K,因此cur非空,压入栈中。由于K节点没有左孩子,所以打印出来。此时cur为空,继续打印栈底元素,也就是节点D。以此类推。最终中序遍历结果是:HKDBEAIFCGJ。
后序遍历
后序遍历就是当节点既没有左孩子又没有右孩子时将节点打印出来,打印完的节点相当于没有了。
public static void postOrderIteration(TreeNode head) {
if (head == null) {
return;
}
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(head);
while (!stack1.isEmpty()) {
TreeNode node = stack1.pop();
stack2.push(node);
if (node.left != null) {
stack1.push(node.left);
}
if (node.right != null) {
stack1.push(node.right);
}
}
while (!stack2.isEmpty()) {
System.out.print(stack2.pop().value + " ");
}
}
代码详解
自己不太会,写罗嗦一点。
创建两个空栈,将头节点A压入栈1中,栈1非空,头节点弹出压入栈2,头节点的左孩子B非空,压入栈1。右孩子C也非空,压入栈1。此时栈1非空,弹出栈顶元素C,压入栈2。C的左右孩子都非空,所以将F、G压入栈1,弹出栈底元素G,压入栈2。G的右孩子非空,压入栈1.栈1非空,弹出栈底元素J压入栈2。J的左右孩子都为空,但是栈1非空,所以弹出栈1的栈底元素F压入栈2.以此类推。最后将栈2中的元素依次打印。后序遍历最后的结果是:KHDEBIFJGCA。