Leetcode. 二叉树的遍历

3 篇文章 0 订阅

方法一:递归遍历

先序遍历

1. 返回值 
2. 终止条件 root == null
3. 单层循环 遍历根节点 + 左孩子 + 右孩子
	void postorder(TreeNode root) {
        if (root != null) {
        	visit(root);             // 访问根节点
            postorder(root.left);
        	postorder(root.right);
        }
	}

中序遍历

	void postorder(TreeNode root) {
        if (root != null) {
            postorder(root.left);
            visit(root);             // 访问根节点
        	postorder(root.right);
        }
	}

后序遍历

	void postorder(TreeNode root) {
        if (root != null) {
            postorder(root.left);
        	postorder(root.right);
        	visit(root);             // 访问根节点
        }
    }

方法二:迭代遍历

1. 迭代遍历中,先序和中序入栈顺序完全相同:一路向左,到头转右
2. 唯一的不同在于访问节点的时机不同,先序在入栈时,中序在出栈时

先序遍历

1. 若左子树不为空,则左子树依次入栈,并访问该节点
2. 若左子树为空,则栈顶元素出栈
3. 判断栈顶元素右子树是否为空,不为空则入栈,即右行一步
	public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode p = root;			// 遍历指针
        while(p!=null || !stack.empty()){
            if(p!=null){			// 左子树不为空,一直向左 
                result.add(p.val);		// 处理节点,值入结果集
                stack.push(p);
                p = p.left;
            }else{					// 左子树为空,出栈并转向右子树	
                p = stack.pop();			
                p = p.right;
            }
        }
        return result;
    }

中序遍历

1. 一路向左
2. 出栈并访问
3. 右节点入栈
public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode p = root;			// 遍历指针
        while(p!=null || !stack.empty()){
            if(p!=null){			// 左子树不为空,一直向左 
                stack.push(p);
                p = p.left;
            }else{					// 左子树为空,出栈并转向右子树	
                p = stack.pop();	
                result.add(p.val);		// 处理节点,值入结果集		
                p = p.right;
            }
        }
        return result;
    }

后序遍历

1. 一路向左
2. 读栈顶元素,有孩子不空且未被访问,执行右子树
3. 否则,出栈并访问
public List<Integer> postTraversal(TreeNode root){
        List result = new LinkedList();		// 结果集
        Stack stack = new Stack();			// 借助栈
        TreeNode p = root;          // 遍历指针
        TreeNode r = null;          // 记录上一个被访问的节点
        while(!stack.empty() || p!=null){
            if(p!=null){			// 一路向左
                stack.push(p);
                p = p.left;
            }else{	
            	//读栈顶元素,有孩子不空且未被访问,执行右子树
                p = (TreeNode) stack.peek();	
                if(p.right != null && p.right != r){	 
                    p = p.right;					
                    stack.push(p);
                    p = p.left;
                }else{							// 否则,出栈并访问
                    p = (TreeNode) stack.pop();
                    result.add(p.val);
                    r=p;
                    p=null;
                }
            }
        }
        return result;
    }

方法三:统一迭代遍历

1. 问题:三种迭代遍历方式代码书写的差异较大,原因是遍历节点和处理节点不能同时通过栈解决。
2. 思路:通过对节点的标记,将遍历节点和处理节点都进行入栈操作,但是对将要处理的节点做好标记
3. 处理方式:将要处理的节点后放入一个空指针座作为标记
4. 好处:三种遍历方式只需要在访问节点后加null做标记,再依此按照遍历顺序重新入栈即可

先序遍历

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();			// 结果集
    	if(root == null){
    	return result;
        Stack<TreeNode> stack = new Stack();				// 借助栈
        stack.push(root);									// 根节点入栈
        while(!stack.empty()){
            TreeNode top = (TreeNode) stack.peek();			// 获取栈顶元素出栈
            if(top != null){								// 栈顶元素不为空,进行访问操作
                stack.pop();        						// 该节点弹出
                if(top.right!=null){						// 按照需要遍历的顺序依此加入左右孩子节点
                    stack.push(top.right);					// 先序遍历:右左中节点依此入栈
                }
                if(top.left != null){
                    stack.push(top.left);
                }
                /*
                1. 在中节点后加null,表示该节点被访问过但是未被处理
                2. 遍历的代码不同之处只是top + null 再次入栈的顺序不同
                */
                stack.push(top);    
                stack.push(null);   						
            }else{                  						// 遇到null说明该节点被访问但尚未处理,操作放入结果集
                stack.pop();								// 将null弹出
                TreeNode temp = (TreeNode) stack.pop();		// 处理节点弹出
                result.add(temp.val);						// 加入结果集
            }
        }
        return result;
}

中序遍历

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();			// 结果集
    	if(root == null){
    	return result;
        Stack<TreeNode> stack = new Stack();				// 借助栈
        stack.push(root);									// 根节点入栈
        while(!stack.empty()){
            TreeNode top = (TreeNode) stack.peek();			// 获取栈顶元素出栈
            if(top != null){								// 栈顶元素不为空,进行访问操作
                stack.pop();        						// 该节点弹出
                if(top.right!=null){						// 按照需要遍历的顺序依此加入左右孩子节点
                    stack.push(top.right);					// 先序遍历:右中左节点依此入栈
                }
                stack.push(top);    
                stack.push(null);   						// 在中节点后加null,表示该节点被访问过但是未被处理
                if(top.left != null){
                    stack.push(top.left);
                }
            }else{                  						// 遇到null说明该节点被访问但尚未处理,操作放入结果集
                stack.pop();								// 将null弹出
                TreeNode temp = (TreeNode) stack.pop();		// 处理节点弹出
                result.add(temp.val);						// 加入结果集
            }
        }
        return result;
}

后序遍历

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();			// 结果集
    	if(root == null){
    	return result;
        Stack<TreeNode> stack = new Stack();				// 借助栈
        stack.push(root);									// 根节点入栈
        while(!stack.empty()){
            TreeNode top = (TreeNode) stack.peek();			// 获取栈顶元素出栈
            if(top != null){								// 栈顶元素不为空,进行访问操作
                // stack.pop();        						// 出栈再入栈,不必操作
                // stack.push(top);    						
                stack.push(null);   						// 在中节点后加null,表示该节点被访问过但是未被处理
                if(top.right!=null){						// 按照需要遍历的顺序依此加入左右孩子节点
                    stack.push(top.right);					// 先序遍历:右中左节点依此入栈
                }
                if(top.left != null){
                    stack.push(top.left);
                }
            }else{                  						// 遇到null说明该节点被访问但尚未处理,操作放入结果集
                stack.pop();								// 将null弹出
                TreeNode temp = (TreeNode) stack.pop();		// 处理节点弹出
                result.add(temp.val);						// 加入结果集
            }
        }
        return result;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值