二叉树遍历总结

简介

线性数据结构比如数组、链表、队列和堆栈都只有一种访问数据的方式,像树这样的非线性数据结构可以有不同的遍历方式。下面总结下二叉树的几种不同遍历方式。

遍历方式

中序遍历

1、先遍历左子树
2、在遍历父节点
3、最后遍历右子树

前序遍历

1、先遍历父节点
2、再遍历左子树
3、最后遍历右子树

后序遍历

1、先遍历左子树
2、再遍历右子树
3、最后遍历父节点

层序遍历

按层遍历,每一层从左到右

代码实现

首先定义树的结构

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(int x) { val = x; }

}

中序实现

递归

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

迭代

迭代需要借助额外的数据结构—栈,先从父节点遍历左子节点,一直遍历到不再存在左子节点,然后从栈顶开始检查,找到每一个节点的右子节点入栈,如果这些右子节点有左节点就继续入栈,重复上面的过程。
栈的作用相当于记住了上次遍历的位置,用来保存下次应该开始遍历的节点。

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

前序实现

递归

public List<Integer> preorderTraversal(TreeNode root){
	if(root == null){
		return new ArrayList<>();
	}
	List<Integer> res = new ArrayList<>();
	preorderTraversal(root, res);
	return res;
}
public void preorderTraversal(TreeNode root, List<Integer> res){
	if(root == null){
		return;
	}
	res.add(root.val);
	preorderTraversal(root.left, res);
	preorderTraversal(root.right, res);
}

迭代

public List<Integer> preorderTraversal(TreeNode root){
	if(root == null){
		return new ArrayList<>();
	}
	Stack<TreeNode> s = new Stack<>();
	List<Integer> res = new ArrayList<>();
	s.push(root);
	
	TreeNode cur = root.left;
	res.add(root.val);
	while(!s.isEmpty() || cur != null){
		while(cur != null){
			s.push(cur);
			res.add(cur.val);
			cur = cur.left;
		}
		cur = s.pop();
		cur = cur.right;
	}
	return res;
}

后序实现

递归

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

还有一种后续递归是先遍历父节点、然后遍历右子树、最后遍历 左子树,得到反转的后序遍历结果,最后反转一下就是正确的遍历结果。后序迭代的写法中用到了类似的想法。

迭代

public List<Integer> postorderTraversal(TreeNode root){
	if(root == null){
		return new ArrayList<>();
	}
	
	Stack<TreeNode> s = new Stack<>();
	List<Integer> res = new ArrayList<>();
	s.push(root);

	TreeNode cur = root.right;
	res.add(root.val);
	while(! s.isEmpty() || cur != null){
		while(cur != null){
			s.push(cur);
			res.add(cur.val);
			cur = cur.right;
		}
		cur = s.pop();
		cur = cur.left;
	}
	Collections.reverse(res);
	return res;
}

层序实现

public List<List<Integer>> levelOrder(TreeNode root){
	List<List<Integer>> res = new ArrayList<>();
	if(root == null) return res;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	q.add(null);//每一层添加一个null标识符
	List<Integer> level = new ArrayList<>();
	while(!q.isEmpty()){
		TreeNode t = q.poll();
		if(t != null){
			level.add(t.val);
			if(t.left != null) q.add(t.left);
			if(t.right != null) q.add(t.right);
		}else{
			if(!q.isEmpty()){
				q.add(null);	
			}
			res.add(level);
			level.clear();
		}
	}
	return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值