代码随想录算法训练营day14|理论基础,递归遍历,迭代遍历,统一迭代

理论基础

二叉树理论基础

递归遍历

递归三要素:

1. 确定递归函数的参数和返回值;

2. 确定终止条件;

3. 确定单层递归的逻辑。

1. 前序遍历(递归)

力扣

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List preorderTraversal(TreeNode root) {
        List list = new ArrayList<>();
        preOrder(root,list);
        return list;
    }
    public void preOrder(TreeNode node,List res){
        if(node==null){
            return;
        }
        res.add(node.val);
        preOrder(node.left,res);
        preOrder(node.right,res);
    }   
}

2. 后序遍历(递归) 

 力扣

class Solution {
    public List postorderTraversal(TreeNode root) {
        List list = new ArrayList<>();
        postOrder(root,list);
        return list;
    }
    public void postOrder(TreeNode node, List res){
        if(node == null){
            return;
        }
        postOrder(node.left,res);
        postOrder(node.right,res);
        res.add(node.val);
    }
}

3. 中序遍历(递归)

力扣

class Solution {
    public List inorderTraversal(TreeNode root) {
        List list = new ArrayList<>();
        inOrder(root,list);
        return list;
    }
    public void inOrder(TreeNode node, List res){
        if(node == null){
            return;
        }
        inOrder(node.left,res);
        res.add(node.val);
        inOrder(node.right,res);
    }
}

迭代遍历

迭代操作:

【栈】先进后出。

(1)处理:把元素放入result数组中;

(2)访问:遍历节点。

1. 前序遍历

入栈顺序:中-右-左

 力扣 

class Solution {
    public List preorderTraversal(TreeNode root) {
        List result = new ArrayList<>();
        if(root==null){
            return result;
        }
        Stack stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.right!=null){
                stack.push(node.right);
            }
            if(node.left!=null){
                stack.push(node.left);
            }
        }
        return result;
    }   
}

2. 中序遍历 

入栈顺序:左-右  

力扣

class Solution {
    public List inorderTraversal(TreeNode root) {
        List result = new ArrayList<>();
        if(root==null){
            return result;
        }
        Stack stack = new Stack<>();
        TreeNode cur = root;
        while(cur!=null || !stack.isEmpty()){
            if(cur!= null){//cur用以访问节点,至最底层
                stack.push(cur);//将访问的节点放进栈
                cur = cur.left;//左
            } else {
                cur = stack.pop();//从栈里弹出的数据,就是要放进result数组的数据
                result.add(cur.val);//中
                cur = cur.right;//右
            }
        }
        return result;
    }
}

 3. 后序遍历

入栈顺序:中-左-右;出栈顺序:中-右-左,然后反转result数组 -> 左-右-中。

力扣

class Solution {
    public List postorderTraversal(TreeNode root) {
        List result = new ArrayList<>();
        if(root==null){
            return result;
        }
        Stack stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.left!=null){
                stack.push(node.left);
            }
            if(node.right!=null){
                stack.push(node.right);
            }
        }
        Collections.reverse(result);//反转result数组
        return result;
    }
}

统一迭代(标记法)

思想:解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的问题。

具体操作:在将访问节点(中节点)放入栈时,把要处理的节点也放入栈,并做标记(放入空指针)。

1. 前序遍历

 力扣 

遍历顺序:中-左-右

压栈顺序:右-左-中

class Solution {
    public List preorderTraversal(TreeNode root) {
        List res = new LinkedList<>();
        if(root==null) return res;
        Stack stack = new Stack<>();
        stack.push(root);
        while(!stack.empty()){
            TreeNode node = stack.peek();
            if (node != null) {
                stack.pop(); //弹出该节点,避免重复操作;
                if (node.right!=null){
                    stack.push(node.right);//添加右节点
                }
                if (node.left!=null){
                    stack.push(node.left);//添加左节点
                }
                stack.push(node);//添加中节点
                stack.push(null); //中节点访问过,但是还没有处理,加入空节点做为标记。
            } else {//遇到空节点的时候,将下一个节点放进结果集
                stack.pop();//弹出空节点
                node = stack.pop();//重新取出栈中元素
                res.add(node.val);//加入到结果集
            }
        }
        return res;
    }   
}

2. 中序遍历 

力扣

遍历顺序:左-中-右

压栈顺序:右-中-左

class Solution {
    public List inorderTraversal(TreeNode root) {
        List res = new ArrayList<>();
        if(root==null) return res;
        Stack stack = new Stack<>();
        stack.add(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node!=null){
                stack.pop();
                if(node.right!=null) stack.push(node.right);
                stack.push(node);
                stack.push(null);
                if(node.left!=null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                res.add(node.val);
            }
        }
        return res;
    }
}

 3. 后序遍历 

力扣

遍历顺序:左-右-中

压栈顺序: 中-右-左

class Solution {
    public List postorderTraversal(TreeNode root) {
        List res = new ArrayList<>();
        if(root==null) return res;
        Stack stack = new Stack<>();
        stack.add(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node!=null){
                stack.pop();
                stack.push(node);
                stack.push(null);
                if(node.right!=null) stack.push(node.right);
                if(node.left!=null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                res.add(node.val);
            }
        }
        return res;
    }
}

你可能感兴趣的:(算法)