代码随想录算法训练营第11天|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代遍历、二叉树的层序遍历

二叉树的递归遍历

二叉树的前中后序递归遍历

//前序遍历
void traversal(TreeNode root){
	if(root == null){
		return;
	}
	res.add(root.val);
	traversal(root.left);
	traversal(root.right);
}
//中序遍历
void traversal(TreeNode root){
	if(root == null){
		return;
	}
	traversal(root.left);
	res.add(root.val);
	traversal(root.right);
}
//后序遍历
void traversal(TreeNode root){
	if(root == null){
		return;
	}
	traversal(root.left);
	traversal(root.right);
	res.add(root.val);
}

——————————————————————————————————————————

二叉树的迭代遍历

因为递归其实就是
每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数。即就是入栈出栈的过程,所以也可以使用栈来迭代遍历二叉树。

//前序遍历迭代法
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new LinkedList<>();
    if (root != null) {
        stack.push(root);
    }

    while (!stack.isEmpty()){
        TreeNode node = stack.pop();
        res.add(node.val);
        if(node.right != null){
            stack.push(node.right);
        }
        if(node.left != null){
            stack.push(node.left);
        }
	}
    return res;
}
//中序遍历迭代法
public List<Integer> inorderTraversal(TreeNode root) {
	List<Integer> res = new ArrayList<>();
	Deque<TreeNode> stack = new LinkedList<>();
	if(root == null){
		return res;
	}
	stack.push(root);
	while(!stack.isEmpty()){
		//先向左找到当前栈顶节点的最左叶子节点,中间的左枝节点全部入栈
		while(stack.peek().left != null){
			stack.push(stack.peek().left);
		}
		//出栈过程,沿着左枝向上出栈,遇到有右孩子的节点就将节点的右孩子加入栈。
		//将最左叶子节点加入结果集合
		TreeNode node1 = stack.pop();
		res.add(node1.val);
		//如果最左叶子节点的右孩子为空,那么就沿着左枝一直向上,即栈一直出栈,这样模拟的是左中的出栈过程
		while(!stack.isEmpty() && node1.right == null){
			node1 = stack.pop();
			res.add(node1.val);
		}
		//如果有右孩子,停止出栈,将右孩子入栈,在下一个循环开始遍历右孩子
		if(node1.right != null){
			stack.push(node1.right);
		}
	}
	return res;
}
//后序遍历迭代法
public List<Integer> postorderTraversal(TreeNode root) {
    //前序遍历是中左右,后序遍历是左右中,那么在前序迭代遍历的基础上,更改一下左右孩子的入栈顺序,变成中右左,最后reverse一下结果集即可
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new LinkedList<>();
    if (root != null) {
        stack.push(root);
    }
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        res.add(node.val);
        if (node.left != null) {
            stack.push(node.left);
        }
        if (node.right != null) {
            stack.push(node.right);
        }

    }
    Collections.reverse(res);
    return res;
}

——————————————————————————————————————————

二叉树的统一迭代遍历 

统一迭代法的核心思想是:对于树中的节点,访问(第一次从栈中出栈获得,此时主要是需要将其的左右孩子节点也加入栈中,该节点也要再次入栈,等待处理)和处理(加入结果集)。
统一迭代法就是在第一次访问节点但是还未处理时,将该节点再次入栈时,再加一个标识,表示该节点已经访问过了,下次再访问到就要进行处理了。
标识方法使用再加一个NULL入栈,这样当获取到NULL出栈时,再出栈一个节点,即为要处理的节点。
这样就能统一前中后序迭代遍历的写法,只需要更改左中右节点的入栈顺序即可。

//统一迭代法(前序遍历)
	public List<Integer> inorderTraversal(TreeNode root) {

		Deque<TreeNode> stack = new LinkedList<>();
		List<Integer> res = new ArrayList<>();
		if (root == null) {
			return res;
		}
		stack.push(root);
		while (!stack.isEmpty()) {
			//获取的不是待处理标识
			if (stack.peek() != null) {
				TreeNode node = stack.pop();
				//中序遍历的入栈顺序为中左右
				if(node.right != null){
					stack.push(node.right);
				}
				stack.push(node);
				stack.push(null);//为node后边再入站一个null,标识node已经访问过但是未处理
				if(node.left != null){
					stack.push(node.left);
				}

			} else {//获取的是待处理标识
				stack.pop();//先将标识null出栈
				res.add(stack.pop().val);//处理节点
			}
		}
		return res;
	}
//统一迭代法(中序遍历)
        public List<Integer> preorderTraversal(TreeNode root) {
            Deque<TreeNode> stack = new LinkedList<>();
            List<Integer> res = new ArrayList<>();
            if (root == null) {
                return res;
            }
            stack.push(root);
            while (!stack.isEmpty()) {
                //获取的不是待处理标识
                if (stack.peek() != null) {
                    TreeNode node = stack.pop();
                    //前序遍历的入栈顺序为右左中
                    if(node.right != null){
                        stack.push(node.right);
                    }
                    if(node.left != null){
                        stack.push(node.left);
                    }
                    stack.push(node);
                    stack.push(null);//为node后边再入站一个null,标识node已经访问过但是未处理
                } else {//获取的是待处理标识
                    stack.pop();//先将标识null出栈
                    res.add(stack.pop().val);//处理节点
                }
            }
            return res;
        }
//统一迭代法(后序遍历)
        public List<Integer> postorderTraversal(TreeNode root) {
            Deque<TreeNode> stack = new LinkedList<>();
            List<Integer> res = new ArrayList<>();
            if (root == null) {
                return res;
            }
            stack.push(root);
            while (!stack.isEmpty()) {
                //获取的不是待处理标识
                if (stack.peek() != null) {
                    TreeNode node = stack.pop();
                    //后序遍历的入栈顺序为中右左
                    stack.push(node);
                    stack.push(null);//为node后边再入站一个null,标识node已经访问过但是未处理
                    if(node.right != null){
                        stack.push(node.right);
                    }
                    if(node.left != null){
                        stack.push(node.left);
                    }

                } else {//获取的是待处理标识
                    stack.pop();//先将标识null出栈
                    res.add(stack.pop().val);//处理节点
                }
            }
            return res;
        }
    }

——————————————————————————————————————————

二叉树的层序遍历 

层序遍历使用队列来存储节点,使得节点先入先出。
每出队一个节点,就将其左右节点入队,这样循环,直到队列中没有节点。
返回结果要将每层节点封装为一个List,因此一次外层while循环中,就遍历一层 。

        public List<List<Integer>> levelOrder(TreeNode root) {
            List<List<Integer>> res = new ArrayList<>();
            Deque<TreeNode> queue = new LinkedList<>();
            if (root == null) {
                return res;
            }
            queue.offer(root);

            while (!queue.isEmpty()) {
                List<Integer> item = new ArrayList<>();
                int size = queue.size();

                while(size-- > 0){
                    TreeNode node = queue.poll();
                    item.add(node.val);
                    if(node.left != null) queue.offer(node.left);
                    if(node.right != null) queue.offer(node.right);
                }
                res.add(item);
            }
            return res;
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值