二叉树的前中后序遍历的递归及非递归算法

144. 二叉树的前序遍历

1.递归

递归时间复杂度:O(N),N为二叉树结点的个数

class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root != null){
            res.add(root.val);
            preorderTraversal(root.left);
            preorderTraversal(root.right);
        }
        return res;
    }
}
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

用递归固然简单,但递归栈的栈深为树的深度,如果遍历一颗单支树,就会得到最坏的空间复杂度O(logN),空间平均复杂度为O(logN),我们可以利用栈来消除递归。

2.先序遍历的非递归实现:
class Solution {
	List<Integer> res = new LinkedList<>();

	public List<Integer> preorderTraversal(TreeNode root) {
		Stack<TreeNode> stack = new Stack<>();
		TreeNode p = root;
		while (p != null || !stack.isEmpty()) {
			if (p != null) {    //一直走到最左下
				res.add(p.val); //访问节点后,压栈
				stack.add(p);
				p = p.left;     
			} else {            //当前栈内节点没有左子树了,那么就访问右孩子节点,右孩子有可能有左子树,用相同的方法处理
				p = stack.pop();
				p = p.right;
			}
		}
		return res;
	}
}

还有一种更直观的方法:

void preorder(Node* root) {
    stack<Node*> myStack;
    Node* p;
    if(root==NULL)return;

    myStack.push(root);

    while(!myStack.empty())
    {
        p=myStack.top();
        myStack.pop();

        visit(p);     处理

        if(p->right!=NULL){myStack.push(p->right);}
        if(p->left!=NULL){myStack.push(p->left);}   
    }

94. 二叉树的中序遍历

1.递归实现:
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root != null){
            inorderTraversal(root.left);
            res.add(root.val);
            inorderTraversal(root.right);
        }
        return res;
    }
}
2.非递归实现:

和先序遍历不同的是将左孩子压栈的时候先不访问根节点,等到弹栈的时候再访问根节点,然后再将右孩子压入栈。

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

145. 二叉树的后序遍历

1.递归实现:
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root != null){
            postorderTraversal(root.left);
            postorderTraversal(root.right);
        	res.add(root.val);
        }
        return res;
    }
}
2.非递归实现:

后序遍历比前两种遍历的非递归实现都要复杂。原因是,我们访问完左节点后,弹栈时并不能立即访问根节点的值,因为遍历顺序为:左->右->根,在访问根节点之前,我们还要确定根节点的右子树是否已经被访问过。

  • 设一个标记节点tag,对于将要弹栈的节点,判断一下这个节点是从左孩子节点还是右孩子节点来的。
class Solution {
    List<Integer> res = new LinkedList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
    	Stack<TreeNode> stack = new Stack<>();
    	if(root == null) {
    		return res;
    	}
    	TreeNode cur = root;	//	当前节点
    	TreeNode tag = null; 	// 标记节点:标记当前节点是从左/右孩子来的
    	while(cur != null || !stack.isEmpty()) {
    		if(cur != null) {	//当前节点不为空,压栈,再看左孩子是否为空,不空继续压栈
    			stack.push(cur);
    			cur = cur.left;
    		}else {	//访问右孩子
    			cur = stack.peek();
    			//当前节点右子树不为空,并且右子树没有访问过
    			if(cur.right != null && cur.right != tag) {
    				cur = cur.right;
    				stack.push(cur);
    				cur = cur.left;
    			}else {	//没有右子树,或者已经访问过了,就访问根节点
    				cur = stack.pop();
    				res.add(cur.val);
    				tag = cur;  //修改标记
    				cur = null;
    			}
    		}
    	}
    	return res;
    }
}

102. 二叉树的层次遍历

BFS

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
    	List<List<Integer>> res = new LinkedList<List<Integer>>();
    	if(root == null)
    		return res;
    	Queue<TreeNode> qu = new LinkedList<>();
    	qu.offer(root);
    	while(!qu.isEmpty()) {
    		int size = qu.size();
    		List<Integer> level = new LinkedList<>();
    		for (int i = 0; i < size; i++) {
        		TreeNode cur = qu.poll();
        		if(cur.left != null)
        			qu.offer(cur.left);
        		if(cur.right != null)
        			qu.offer(cur.right);
        		level.add(cur.val);
			}
    		res.add(level);
    	}
    	return res;
    }
    /*
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }*/
}
//C++版本
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(!root){  //空树
            return res;
        }
        queue<TreeNode*> qu;
        qu.push(root);
        while(!qu.empty()){
            int size = qu.size();
            res.push_back(vector <int> ());
            for(int i = 1; i <= size; i++){
                auto node = qu.front();
                qu.pop();
                res.back().push_back(node->val);
                if(node->left) qu.push(node->left);
                if(node->right) qu.push(node->right);
            }
        }
        return res;
    }
};

107. 二叉树的层次遍历 II

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
    	List<List<Integer>> res = new LinkedList<List<Integer>>();
    	if(root == null)
    		return res;
    	Queue<TreeNode> qu = new LinkedList<>();
    	qu.offer(root);
    	while(!qu.isEmpty()) {
    		int size = qu.size();
    		List<Integer> level = new LinkedList<>();
    		for (int i = 0; i < size; i++) {
        		TreeNode cur = qu.poll();
        		if(cur.left != null)
        			qu.offer(cur.left);
        		if(cur.right != null)
        			qu.offer(cur.right);
        		level.add(cur.val);
			}
    		res.add(0, level);	//实际上还是从上往下BFS,不过添加的时候是在0处添加
    	}
    	return res;
    }
}

也可以用addfirst(头插),一个意思。


637. 二叉树的层平均值

利用层次遍历计算每一层的平均值

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new LinkedList<>();
    	if(root == null)
    		return res;
    	Queue<TreeNode> qu = new LinkedList<>();
    	qu.offer(root);
    	while(!qu.isEmpty()) {
    		int size = qu.size();
    		double sum = 0;
    		for (int i = 0; i < size; i++) {
        		TreeNode cur = qu.poll();
        		if(cur.left != null)
        			qu.offer(cur.left);
        		if(cur.right != null)
        			qu.offer(cur.right);
        		sum += cur.val;
			}
    		res.add(sum/size);
    	}
    	return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值