// 递归遍历写法,以前序遍历为例
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
traverse(root, result);
return result;
}
public void traverse(TreeNode p, List<Integer> result) {
if (p == null) {
return;
}
// 其他遍历调整这里的语句顺序即可
result.add(p.val);
traverse(p.left, result);
traverse(p.right, result);
}
前序非递归
// 通过非递归遍历
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode p = root;
while (p != null || ! stack.isEmpty()) {
while (p != null) {
// 前序遍历,所以先保存结果
result.add(p.val);
stack.push(p);
p = p.left;
}
// pop出栈顶元素
if (! stack.isEmpty()) {
p = stack.pop();
p = p.right;
}
}
return result;
}
中序非递归
// 思路:通过stack 保存已经访问的元素,用于原路返回
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode p = root;
while (p != null || ! stack.isEmpty()) {
if (p != null) {
stack.push(p);
p = p.left;
} else {
TreeNode node = stack.pop();
result.add(node.val);
p = node.right;
}
}
return result;
}
后序非递归
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
// 通过lastVisit标识右子节点是否已经弹出
TreeNode lastVisit = root;
while (p != null || !stack.isEmpty()) {
while (p != null) {
stack.push(p);
p = p.left;
}
//查看当前栈顶元素
p = stack.peek();
//如果其右子树也为空,或者右子树已经访问,则可以访问
if (p.right == null || p.right == lastVisit) {
result.add(p.val);
stack.pop();
// 标记当前这个节点已经弹出过
lastVisit = p;
p = null;
} else {
//否则继续遍历右子树
p = p.right;
}
}
return result;
}
注意点
核心就是:根节点必须在右节点弹出之后,再弹出
DFS 深度搜索
给定一个二叉树,返回所有从根节点到叶子节点的路径。
public List<String> binaryTreePaths(TreeNode root) {
StringBuilder path = new StringBuilder();
List<String> paths = new LinkedList<>();
dfs(root, path, paths);
return paths;
}
public void dfs(TreeNode p, StringBuilder path, List<String> paths) {
if (p == null) {
return;
}
path.append(p.val);
// 当前节点是叶子节点
if (p.left == null && p.right == null) {
// 把路径加入结果
paths.add(path.toString());
} else {
path.append("->");
// 这里需要复制创建新的StringBuilder对象
dfs(p.left, new StringBuilder(path), paths);
dfs(p.right, new StringBuilder(path), paths);
}
}
BFS 层次遍历
public List<Integer> levelOrder(TreeNode root) {
List<Integer> result = new LinkedList<>();
if (root == null) {
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode p = queue.pop();
result.add(p);
if (p.left != null) {
queue.add(p.left);
numList.add(p.left.val);
}
if (p.right != null) {
queue.add(p.right);
numList.add(p.right.val);
}
}
return result
}
二叉树分治
先分别处理局部,再合并结果
分治法模板
递归返回条件
分段处理
合并结果
public ResultType traversal(TreeNode root) {
// null or leaf
if (root == null) {
// do something and return
}
// Divide
ResultType left = traversal(root.Left)
ResultType right = traversal(root.Right)
// Conquer
ResultType result = Merge from left and right
return result
}
典型示例
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
public boolean isValidBST(TreeNode root) {
return divideAndConquer(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean divideAndConquer(TreeNode p, long min, long max) {
if (p == null) return true;
// 返回条件
if (p.val <= min || max <= p.val) {
return false;
}
// 分治(Divide)
boolean left = divideAndConquer(p.left, min, p.val);
boolean right = divideAndConquer(p.right, p.val, max);
// 合并结果(Conquer)
return left && right;
}