二叉树的遍历方式
如图,这是一个二叉树

什么是递归序
-
将上面的二叉树递归,每次递归打印一次就变成了一个递归序
- 以2为头节点的子树遍历:2,4,4,4,2,0,0,0,2
- 由于每个节点都有两个指针。所以都会经历三次打印
- (来到该节点打印一次)
- (该节点的左子节点打印完成之后返回该节点打印一次)
- (该节点的右子节点打印完成之后返回该节点打印一次)
二叉树排序的分类
先序遍历
- 先从头节点开始,依次打印左子节点和右子节点的值,简称"头左右"
- 实质上就是递归序每次只打印第一次出现的数字
- 比如说以2为头节点的子树遍历:2,4,4,4,2,0,0,0,2,每次只打印第一次出现的数字:2,4,0。
- 依次类推,这整颗数上遍历就是1,3,2,4,0,5,8,12,6,7,17,15,9,13,19
中序遍历
- 先从左子节点开始,依次打印头节点和右子节点的值,简称"左头右"
- 实际上就是递归序每次只打印第二次出现的数字
- 以2为头节点的子树遍历:2,4,4,4,2,0,0,0,2。每次只打印第二次出现的数字:4,2,0。
- 整颗树上就是:4,2,0,3,8,5,12,17,7,15,6,13,9,19
后序遍历
- 先遍历左右两个子节点的值,最后才是头节点的值,简称"左右头"
- 实际上就是递归序每次只打印第三次数显的数字
- 以2为头节点的子树遍历:2,4,4,4,2,0,0,0,2。每次只打印第三次数显的数字:4,0,2。
- 整棵树上的遍历就是:4,0,2,8,12,5,3,17,12,7,13,19,9,6,1
代码实现
- 二叉树实现遍历最主要的方式还是递归。同时也可以借助栈来实现遍历。在这里介绍两种方式
递归方式
-
前序
-
public static void perOrderRecur(Node head) { if (head == null) { return; } System.out.print(head.value + " "); perOrderRecur(head.left); perOrderRecur(head.right); } -
因为每个节点经历三次打印(这个数,左子节点完成之后,右子节点完成之后)所以在第一次经历这个数字的时候打印即可。具体一点就是在左右子节点完成这个遍历过程之前就打印。
-
-
中序
-
public static void inOrderRecur(Node head) { if (head == null) { return; } inOrderRecur(head.left); System.out.print(head.value + " "); inOrderRecur(head.right); } -
同理,在左子节点完成之后打印,就是只在第二次打印。就可以完成中序遍历
-
-
后序
-
public static void posOrderRecur(Node head) { if (head == null) { return; } posOrderRecur(head.left); posOrderRecur(head.right); System.out.print(head.value + " "); } -
只在第三次打印即可,即最后一次打印就可完成后续遍历
-
非递归方式
用这种方式是以空间换时间的方式,降低了时间复杂度的同时,提高了空间复杂度。不过在某些特定的场合,这种方式无疑是最好的。总的来说两种方式各有优缺点。想用哪一个取决于你们。
-
前序
-
public static void perOrderUnRecur(Node head) { System.out.print("per-order: "); if (head != null) { Stack<Node> stack = new Stack<>(); stack.add(head); while (!stack.isEmpty()) { head = stack.pop(); System.out.print(head.value+" "); if (head.right != null) { stack.push(head.right); } if (head.left != null) { stack.push(head.left); } } } System.out.println(); } -
借助一个栈。先将头弹出,然后栈中依次放入右、左。这样弹出来就是左、右。头早早的弹出。所以最终就是头左右 前序遍历
-
-
中序
-
public static void inOrderUnRecur(Node head) { System.out.print("in-order: "); if (head != null) { Stack<Node> stack = new Stack<>(); stack.add(head); while (!stack.isEmpty() || head != null) { if (head != null) { stack.push(head); head = head.left; }else{ head = stack.pop(); System.out.print(head.value + " "); head = head.right; } } } System.out.println(); } -
每棵子树整棵树左边界进栈,一次弹出的过程中打印,直到最后一个节点的左子节点为空。执行else里面的内容。
- 将head重新赋值为栈中最顶上的元素即这个元素(null)的父节点(具体可以看if里面)。然后打印(null)的父节点,然后这个head重新赋值为父节点的右子节点,重复这个行为。
-
-
后序
-
public static void posOrderUnRecur(Node head) { System.out.print("pos-order: "); if (head != null) { Stack<Node> s1 = new Stack<>(); Stack<Node> s2 = new Stack<>(); s1.push(head); while (!s1.isEmpty()) { head = s1.pop(); s2.push(head); if (head.left != null) { s1.push(head.left); } if (head.right != null) { s1.push(head.right); } } while (!s2.isEmpty()) { System.out.print(s2.pop().value + " "); } } System.out.println(); } -
这是准备了2个栈空间,一个栈(s1)执行的原理和先序遍历一样,只不过顺序换成了先压左子节点,再压右子节点,在此之前将头节点率先压入了s2中,在s1放的顺序是左右,倒入s2的顺序就是右左,s2的最底下有头,所以s2的压栈顺序是头右左,所以s2弹出的顺序是左右头。即可完成后序遍历
-

浙公网安备 33010602011771号