Base:
树的四种遍历
写递归很简单
public List<Integer> inorderTraversalRecur(TreeNode root) {
List<Integer> res = new ArrayList<>(); // 遍历结果为一个ArrayList
inorder(root,res); // 新开一个inorder方法递归
return res;
}
private void inorder(TreeNode root, List<Integer> res) {
if (root==null) return; // 递归最小子问题是当前节点已经往下走到了叶子结点以下的空节点,直接return
inorder(root.left,res); // 先访问左子树
res.add(root.val); // 再进行访问当前结点的操作
inorder(root.right,res); // 最后访问右子树
}
迭代方法一般需要借助一个栈来实现(因为是dfs)
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while (node!=null || !stack.isEmpty()){ // 栈不为空说明还有父亲结点没有处理
while (node!=null){ // 结点不为空则先入栈,往左子树走
stack.push(node);
node = node.left;
}
node = stack.pop();
res.add(node.val); // 处理当前结点
node = node.right; // 往右子树走
}
return res;
}
递归和中序遍历类似,只在左右子树和根节点的访问顺序那里有不同
public List<Integer> preorderTraversalRecur(TreeNode root) {
List<Integer> res = new ArrayList<>(); // 遍历结果为一个ArrayList
preOder(root,res); // 新开一个preOder方法递归
return res;
}
private void preOder(TreeNode root, List<Integer> res) {
if (root==null) return; // 递归最小子问题是当前节点已经往下走到了叶子结点以下的空节点,直接return
res.add(root.val); // 先进行访问当前结点的操作
preOder(root.left,res); // 再访问左子树
preOder(root.right,res); // 最后访问右子树
}
迭代也是借助栈,调换一下左子树和当前结点的访问顺序
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<>();
TreeNode p = root;
while (p!=null || !stack.isEmpty()){ // 栈不为空说明还有父亲结点没有处理
while (p!=null){ // 结点不为空则先访问当前结点
res.add(p.val);
stack.push(p);
p = p.left; // 当前结点处理后把当前结点压栈后再往左子树走
}
p = stack.pop().right; // 处理完根节点和左子树结点最后再出站访问右子树
}
return res;
}
后序递归也是大同小异
public List<Integer> postorderTraversalRecur(TreeNode root) {
List<Integer> res = new ArrayList<>(); // 遍历结果为一个ArrayList
postOrder(root,res); // 新开一个postOrder方法
return res;
}
private void postOrder(TreeNode root, List<Integer> res) {
if (root==null) return; // 递归最小子问题是当前节点已经往下走到了叶子结点以下的空节点,直接return
postOrder(root.left,res); // 先访问左子树
postOrder(root.right,res); // 再访问右子树
postOrder.add(root.val); // 最后进行访问当前结点的操作
}
迭代稍微复杂一些
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode last = null;
while (cur!=null || !stack.isEmpty()){
while (cur!=null) {
stack.push(cur);
cur = cur.left; // 先往左子树走,把结点压栈
}
cur = stack.peek(); // stack.peek()只是取出栈顶元素,要和stack.pop()弹出栈顶元素区分开来;
// 当前结点没有右子树了,或者上次访问的点是右孩子(last),说明右子树已经遍历过了,那么就访问当前结点,并把last设置为当前结点
if (cur.right ==null||cur.right==last){
res.add(cur.val);
stack.pop();
last = cur; // 变量last用于保存当前栈顶所弹出的元素,判断 curr.right == last 是为了避免重复访问同一个元素而陷入死循环当中。
cur = null;
}else{
cur=cur.right;
}
}
return res;
}