目录
1. 概述
遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
2. 二叉树有五种遍历方法
首先要知道,不管是哪种遍历方法,都是左子树在右子树的前面,只是根的位置不同。
- 前根遍历
- 中根遍历
- 后根遍历
- 广度优先遍历
- 深度优先遍历
3. 先序遍历/深度优先遍历
首先访问根,再先序遍历左(右)子树,最后先序遍历右(左)子树。
前根遍历实际上就是深度优先遍历
3-1. 递归遍历
/**
* 前根遍历 先打印根 根 - 左 - 右
* @param root 树根
*/
private static void prefixLoop(TreeNode root) {
// 递归终止条件
if (root == null)
return;
// 输出 根
System.out.print(root.value + " ");
// 向左遍历
prefixLoop(root.left);
// 向右遍历
prefixLoop(root.right);
}
3-2. 迭代遍历
/**
* 深度优先
* @param root 树根
*/
private static void depthFirst(TreeNode root) {
// 定义临时栈
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
// 将根节点添加到栈中
stack.addLast(root);
while (!stack.isEmpty()) {
TreeNode node = stack.removeLast();
// 输出 根
System.out.print(node.value + " ");
// 先遍历右子树(栈: LILO)
if (node.right != null) {
stack.addLast(node.right);
}
// 后遍历左子树
if (node.left != null) {
stack.addLast(node.left);
}
}
}
4. 中序遍历
首先中序遍历左(右)子树,再访问根,最后中序遍历右(左)子树。
/**
* 中序遍历 中间是根 左 - 根 - 右
* @param root 树根
*/
private static void infixLoop(TreeNode root) {
// 递归终止条件
if (root == null)
return;
// 向左遍历
infixLoop(root.left);
// 输出 根
System.out.print(root.value + " ");
// 向右遍历
infixLoop(root.right);
}
5. 后序遍历
首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根。
/**
* 后根遍历 最后是根 左 - 右 - 根
* @param root 树根
*/
private static void subfixLoop(TreeNode root) {
// 递归终止条件
if (root == null)
return;
// 向左遍历
subfixLoop(root.left);
// 向右遍历
subfixLoop(root.right);
// 输出 根
System.out.print(root.value + " ");
}
6. 广度优先遍历
即按照层次访问,通常用队列来做。访问根,访问子女,再访问子女的子女(越往后的层次越低)(两个子女的级别相同)。
/**
* 广度优先遍历
* @param root 树根
*/
private static void breadthFirst(TreeNode root) {
// 定义队列
ArrayDeque<TreeNode> queue = new ArrayDeque<>();
// 添加 根 到队列中
queue.addLast(root);
while (!queue.isEmpty()) {
TreeNode node = queue.removeFirst();
// 输出 根
System.out.print(node.value + " ");
// 添加左子树到队列( 队列: LIFO )
if (node.left != null) {
queue.addLast(node.left);
}
// 添加右子树到队列
if (node.right != null) {
queue.addLast(node.right);
}
}
}
不要因为知识简单就忽略, 不积跬步无以至千里.