二叉树的遍历
给你二叉树的根节点 root ,返回其节点值的前序、中序、后序、层序遍历。
使用迭代的方式实现递归函数,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来
前序遍历-递归与迭代
public void preOrder(TreeNode root, List<Integer> res) {
//根左右
if (root == null) {
return;
}
res.add(root.val);
preOrder(root.left, res);
preOrder(root.right, res);
}
---------------------------------------------------------------------
public List<Integer> preorderTraversal(TreeNode root) {
// 使用栈模拟递归
List<Integer> list = new ArrayList<Integer>();
if (root != null) {
Stack<TreeNode> stack = new Stack<>();
stack.add(root);// 根节点压入栈中
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (node != null) {
list.add(node.val);
// 这里需要先把右子树先压入栈中(因为需要先弹出左子树)
stack.push(node.right);
stack.push(node.left);
}
}
}
return list;
}
中序遍历-递归与迭代
public void inOrder(TreeNode root, List<Integer> res) {
//左根右
if (root == null) {
return;
}
inOrder(root.left, res);
res.add(root.val);
inOrder(root.right, res);
}
---------------------------------------------------------------------
public List<Integer> inorderTraversal(TreeNode root) {
// 使用栈模拟递归
List<Integer> list = new ArrayList<Integer>();
if (root != null) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (!stack.isEmpty() || root != null) {// 同时需要找到最左边的节点
if (root != null) {// 一直找最左边的节点并把节点压入栈中
stack.push(root);
root = root.left;
} else {// 找到最左边的节点
root = stack.pop();// 弹出最左的节点
list.add(root.val);
root = root.right;// 最左的节点可能有右子节点,也可能没有
}
}
}
return list;
}
后序遍历-递归与迭代
public void postOrder(TreeNode root, List<Integer> res) {
//左右根
if (root == null) {
return;
}
postOrder(root.left, res);
postOrder(root.right, res);
res.add(root.val);
}
---------------------------------------------------------------------
public List<Integer> postorderTraversal(TreeNode root) {
// 左右根
List<Integer> list = new ArrayList<Integer>();
TreeNode prev = null;// 记录是否被打印
if (root != null) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (!stack.isEmpty() || root != null) {// 同时需要找到最左边的节点
while (root != null) {// 一直找最左边的节点并把节点压入栈中
stack.push(root);
root = root.left;
}
root = stack.pop();// 弹栈
if (root.right == null || root.right == prev) {// 右子节点为空或已经加入list
list.add(root.val);
prev = root;// 记录右子节点已经加入list
root = null;// 赋值为null,防止进入下次循环
} else {
// 有右子节点或右子节点未加入list,则将该节点入栈并指向该右子节点
stack.push(root);
root = root.right;
}
}
}
return list;
}
层序遍历-递归与迭代
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
// 可以发现,满二叉树节点的下标都是固定的(根节点的序号为i,则左子树序号为2*i,右子树为2*i+1)
if (root == null) {
return new ArrayList<List<Integer>>();
}
ArrayList<List<Integer>> list = new ArrayList<List<Integer>>();
return dfs(root, 1, list);
}
private List<List<Integer>> dfs(TreeNode root, int i, ArrayList<List<Integer>> list) {
if (list.size() < i) {
// 当list大小不能放下新list时,需要使用add扩容
list.add(new ArrayList<Integer>());
}
list.get(i - 1).add(root.val);// 放入当前节点的值
if (root.left != null) {
dfs(root.left, i + 1, list);
}
if (root.right != null) {
dfs(root.right, i + 1, list);
}
return list;
}
}
---------------------------------------------------------------------
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<List<Integer>>();
}
// 使用迭代实现层序遍历需要使用队列
ArrayList<List<Integer>> list = new ArrayList<List<Integer>>();
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
int size = q.size();// 获取当前层的节点数(当前队列长度=前层的节点数)
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 0; i < size; i++) {// 这里也是一样的必须使用size变量
TreeNode node = q.remove();// 取出队列节点
temp.add(node.val);
if (node.left != null) {
q.add(node.left);
}
if (node.right != null) {
q.add(node.right);
}
}
// 将此层的节点放入list
list.add(temp);
}
return list;
}