二叉树的遍历
概念
二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。
1.1二叉树的深度优先遍历和广度优先遍历
树遍历的本质是将非线性结构线性化
深度优先遍历
二叉树的深度优先遍历,分为如下三种:(先左后右)
- 1.先序遍历,访问根结点,先序遍历左子树,先序遍历右子树
- 2.中序遍历,中序遍历左子树,访问根结点,中序遍历右子树
- 3.后序遍历,后序遍历左子树,后续遍历右子树,访问根结点
广度优先遍历
与深度优先遍历不同的是,广度优先遍历是先搜索所有兄弟和堂兄弟结点再搜索子孙结点。而深度优先遍历则是先搜索一个结点的所有子孙结点,再去搜索这个结点的兄弟结点。广度优先遍历,不需要使用递归,借助队列来实现。
1.2前序遍历
先输出当前结点的数据,再依次遍历输出左结点和右结点
前序遍历图示
前序遍历的递归实现
public static void front(TreeNode root) {
if (root==null) {
return ;
}
System.out.println(root.val);
front(root.left);
front(root.right);
}
前序遍历的非递归实现
public static void frontFeiDiGui(TreeNode root) {
if (root==null) {
return ;
}
Stack<TreeNode> stack = new Stack<>();
while (root!=null||!stack.isEmpty()) {
while (root!=null) {
System.out.println(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop().right;
}
}
1.3中序遍历
先遍历输出左结点,再输出当前结点的数据,再遍历输出右结点
中序遍历图示
中序遍历的递归实现
public static void middleDiGui(TreeNode root) {
if (root==null) {
return ;
}
frontDiGui(root.left);
System.out.println(root.val);
frontDiGui(root.right);
}
中序遍历的非递归实现
public static void middleFeiDiGui(TreeNode root) {
if (root==null) {
return ;
}
Stack<TreeNode> stack = new Stack<>();
while (root!=null||!stack.isEmpty()) {
while (root!=null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
System.out.println(root.val);
root = root.right;
}
}
1.4后序遍历
先遍历输出左结点,再遍历输出右结点,最后输出当前结点的数据
后序遍历图示
后续遍历的递归实现
public static void behindDiGui(TreeNode root) {
if (root==null) {
return ;
}
frontDiGui(root.left);
frontDiGui(root.right);
System.out.println(root.val);
}
后序遍历的非递归实现
/*后序遍历时,分别从左子树和右子树共两次返回根结点(用tag表示次数),
* 只有从右子树返回时才访问根结点,所以增加一个栈标记到达结点的次序。
*/
public static void behindFeiDiGui(TreeNode root) {
if (root==null) {
return ;
}
Stack<TreeNode> stack = new Stack<>();
Stack<Integer> tag = new Stack<>();
while (root!=null||!stack.isEmpty()) {
while (root!=null) {
stack.push(root);
tag.push(1);//第一次访问
root = root.left;
}
if (tag.peek()==1) {
tag.pop();
tag.push(2);//第二次访问
root = stack.pop().right;
} else {
System.out.println(stack.pop().val);
tag.pop();
}
}
}
1.5层序遍历
从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中按从左到右的顺序对结点逐个访问
层序遍历的实现(用队列数据结构)
public static void sequence(TreeNode root) {
if (root==null) {
return ;
}
LinkedList<TreeNode> list = new LinkedList<>();
list.add(root);
while(!list.isEmpty()) {
root = list.poll();
System.out.println(root.val);
if (root.left!=null) {
list.add(root.left);
}
if (root.right!=null) {
list.add(root.right);
}
}
}
1.6二叉树根据其余两种遍历的结果推理另外一种遍历结果
比如你知道一个程序的先序遍历是ABCDEFG 中序遍历是CBDAEGF让你推算出后序遍历,因为先序遍历的顺序是根-左-右 那么我们看先序遍历ABCDEFG,那么A就是根结点,再看中序遍历CBDAEGF,根据中序遍历的左-根-右看出A左边CBD的都是左子树,右边的EGF是左子树,然后对先序遍历划分 A/BCD/EFG,对左子树CBD 由先序遍历中的A/BCD/EFG可以看出BCD中B在前面 则B是左子树的根 C是下一行的左子树,同理可对EFG分析,画出图如下:
A
/ \
B E
/\ \
C D F
/
G
那么后序遍历CDBGFEA