树的遍历
树的前序遍历,中序遍历,后序遍历以及层序遍历的java代码实现,每种都有递归和循环两种方法。
对于树结构的定义如下所示:
/**
* 树结构的定义
*/
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
前序遍历
- 访问根结点。
- 前序遍历左子树。
- 前序遍历右子树
递归方法:
/**
* 前序遍历,递归方法
*/
public static void preorderRec(TreeNode root) {
if (root != null) {
System.out.print(root.val);
preorderRec(root.left);
preorderRec(root.right);
}
}
迭代方法:
/**
* 前序遍历迭代方法
*/
public static void preorderIte(TreeNode root) {
if (root != null) {
// 用于存储遍历过的结点
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
// 当前节点与栈都不为空
while (cur != null || !stack.isEmpty()) {
// 如果当前节点不为空,输出值,压入栈,移动到左子树
if (cur != null) {
// 前序遍历根节点首先输出,所以输出在最前
System.out.print(cur.val);
// 将cur入栈是为了后面遍历右子树
stack.push(cur);
cur = cur.left;
} else {
// 如果当前元素为空,回退到父节点,再遍历右子树,然后父节点就可以出栈了,因为他的左右子树都遍历完成了
cur = stack.pop();
cur = cur.right;
}
}
}
}
中序遍历
- 中序遍历左子树。
- 访问根结点。
- 中序遍历右子树
递归方法:
/**
* 中序遍历,循环
*/
private static void inOrderRec(TreeNode root) {
if (root == null) {
return;
}
inOrderRec(root.left);
System.out.print(root.val);
inOrderRec(root.right);
}
迭代方法:
/**
* 中序遍历,循环
*/
private static void inOrderIte(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
// 先是左子树
cur = cur.left;
} else {
// 到达叶子节点,弹出栈,输出,在遍历右子树
cur = stack.pop();
// 跟前序遍历相反,这个是出栈输出
System.out.print(cur.val);
cur = cur.right;
}
}
}
后序遍历
- 后序遍历左子树。
- 后序遍历右子树
- 访问根结点。
递归方法:
/**
* 后序遍历,递归
*/
private static void postOrderRec(TreeNode root) {
if (root == null) {
return;
}
postOrderRec(root.left);
postOrderRec(root.right);
System.out.print(root.val);
}
循环方法
/**
* 后序遍历,迭代
* 后序遍历的方法与前序遍历与中序遍历的方法不太相同
*/
private static void postOrderIte(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
// 新增加一个栈,利用栈先进后出的原则,先放入根节点,然后放入右节点,最后放入左节点
Stack<TreeNode> output = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
output.push(cur);
stack.push(cur);
// 先进后出,所以先是右边
cur = cur.right;
} else {
// output不出栈,stack只是为了帮助找到左子树
cur = stack.pop();
cur = cur.left;
}
}
while (!output.isEmpty()) {
System.out.print(output.pop().val);
}
}
层序遍历
按照层的顺序来遍历
递归方法:
/**
* 层序遍历, 递归方法
* 首先层序遍历需要按照层来划分,也就是深度,
* 然后围绕深度输出
*/
public static void levelOrderRec(TreeNode root) {
if (root == null) {
return;
}
// 分层遍历
for (int i = 1; i <= depthIte(root); i++) {
levleOrder(root, i);
}
}
/**
* 层序遍历辅助函数,每遍历一层level减1,直到level为1,输出这一层的元素值
*/
private static void levleOrder(TreeNode root, int level) {
if (root == null || level < 1) {
return;
}
// 这里的level不是指树的层,指还剩的层数
if (level == 1) {
System.out.print(root.val);
}
// 每向下遍历一层,层数就减1,直到层数为1,遍历的就是这一层,输出节点的值
levleOrder(root.left, level - 1);
levleOrder(root.right, level - 1);
}
/**
* 递归方法计算树深度
*/
private static int depthRec(TreeNode root) {
if (root == null) {
return 0;
}
int l = depthRec(root.left);
int r = depthRec(root.right);
if (l > r) {
return l + 1;
} else {
return r + 1;
}
}
循环方法
/**
* 层序遍历,非递归方法
* 利用队列这个先进先出的数据结构
* 入队的时候就是按照层的顺序入队,出队也 非常方便
* LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用
*/
public static void levelOrderIte(TreeNode root) {
if (root == null) {
return;
}
TreeNode cur;
// LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
// 每次都是当前节点出队,然后存入当前节点的左右子节点
while (queue.size() != 0) {
cur = queue.poll();
System.out.print(cur.val);
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
}
This blog is under a CC BY-NC-SA 4.0 Unported License
本文链接:https://ahscuml.github.io/树的遍历/