二叉树的遍历
深度遍历
三种遍历最简单直接的方法就是递归,直接按照顺序编写。
前序遍历
根结点->左子树->右子树
上图遍历为12457836
- 递归
public List<Integer> preorder(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
preHelper(root,reslist);
return reslist;
}
public void preHelper(TreeNode root,List<Integer>reslist){
if (root!=null){
reslist.add(root.val);
if (root.left!=null){
preHelper(root.left,reslist);
}
if (root.right!=null){
preHelper(root.right,reslist);
}
}
}
- 迭代
使用栈辅助存储。因为是根左右,而且栈是先进后出,所以每次弹出栈顶(记录)时,先把右子结点放入栈,再将左子结点入栈。这样,左子结点比右子结点先出栈。例如:
- 1入栈。栈:1
- 1出栈,右子结点3入栈,左2入栈。栈:23
- 2出栈,右5左4入栈,栈:453
- 4出栈,没有子结点,栈:53
- 5出栈,右8左7入栈,栈:783
- 7出栈,栈:83
- 8出栈,栈:3
- 3出栈,右6入栈,栈:6
- 6出栈,栈
- 因为栈空,所以结束。
顺序为栈弹出顺序。
public List<Integer> preorderIter(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
Stack<TreeNode> s=new Stack<>();
TreeNode cur=root;
s.push(root);
while (!s.isEmpty()){
cur=s.pop();
reslist.add(cur.val);
if (cur.right!=null){
s.push(cur.right);
}
if (cur.left!=null){
s.push(cur.left);
}
}
return reslist;
}
中序遍历
左子树->根结点->右子树
上图遍历为42758136
- 递归
public List<Integer> inorder(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
inHelper(root,reslist);
return reslist;
}
public void inHelper(TreeNode root,List<Integer>reslist){
if (root!=null){
if (root.left!=null){
inHelper(root.left,reslist);
}
reslist.add(root.val);
if (root.right!=null){
inHelper(root.right,reslist);
}
}
}
- 迭代
public List<Integer> inorderIter(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
Stack<TreeNode> s=new Stack<>();
TreeNode cur=root;
while (cur!=null||!s.isEmpty()){
while (cur!=null){
s.push(cur);
cur=cur.left;
}
cur=s.pop();
reslist.add(cur.val);
cur=cur.right;
}
return reslist;
}
使用栈辅助。先把所有左子结点入栈,然后弹出栈顶(记录),再将该结点右子结点入栈,循环。例如:
- 1入栈,2入栈,4入栈。栈:421
- 4出栈。栈:21
- 2出栈,右5入栈。栈:51
- 7入栈,栈:751
- 7出,栈:51
- 5出,8入,栈:81
- 8出,栈:1
……
后序遍历
左子树->右子树->根结点
上图遍历为47852631
- 递归
public List<Integer> postorder(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
postHelper(root,reslist);
return reslist;
}
public void postHelper(TreeNode root,List<Integer>reslist){
if (root!=null){
if (root.left!=null){
postHelper(root.left,reslist);
}
if (root.right!=null){
postHelper(root.right,reslist);
}
reslist.add(root.val);
}
}
- 迭代
一种讨巧的方式。前序遍历是以根右左的方式入栈,出来的结果是根左右。所以后序遍历就可以以根左右的方式入栈,出来的结果是根右左。然后将结果翻转,就变成了左右根!
public List<Integer> postorderIter(TreeNode root){
List<Integer>reslist=new ArrayList<>();
if (root==null)return reslist;
Stack<TreeNode> s=new Stack<>();
TreeNode cur=root;
s.push(root);
while (!s.isEmpty()){
cur=s.pop();
reslist.add(0,cur.val);
if (cur.left!=null)s.push(cur.left);
if (cur.right!=null)s.push(cur.right);
}
return reslist;
}
例如:
- 根结点1入栈,栈:1
- 1弹出,1的左右子结点入栈,栈:32
- 3出栈,右6入栈,栈:62
- 6弹出,栈:2
- 2弹出,左右45入栈,栈:54
- 5弹出,左右78入栈,栈:874
- 8,7,4接连弹出,栈空
遍历即为栈弹出的相反顺序。
广度遍历(层次遍历)
这种遍历方式也就是一层一层遍历。
上图遍历为12345678。
使用队列的数据结构帮助遍历,先将根结点加入队列。
只要队列不空,就将队列的首个元素弹出。再将该元素的左右结点加入队列。这样就实现了按照层次顺序加入队列。例如:
- 首先将1加入队列,此时队列:1;
- 然后将1弹出,把1的左右结点2和3加入队列,此时队列:23;
- 紧接着将2弹出,把2的左右结点4和5加入队列,此时队列:345;
- 将3弹出,因为3没有左结点,所以加入3的右结点6,此时队列:456;
- 将4弹出,4没有子结点,队列不加入元素:56;
- 将5弹出,加入5的左右结点78:678;
- 将6弹出,6也没有结点,队列:78;
- 弹出7,7也没有子结点,队列:8;
- 弹出8,8也没有子结点,队列:;
- 因为此时队列为空,所以循环结束。
遍历顺序就是队列的弹出顺序12345678。
public List<Integer> levelOrder(TreeNode root) {
List<Integer>resList=new ArrayList<>();
if (root==null)return resList;
LinkedList<TreeNode> q=new LinkedList<>();
q.add(root);
while (!q.isEmpty()){
TreeNode cur=q.remove();
resList.add(cur.val);
if (cur.left!=null){
q.add(cur.left);
}
if (cur.right!=null){
q.add(cur.right);
}
}
return resList;
}
稍加修改,就可以将每一层分开,输出1,23,456,78
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>>resList=new ArrayList<>();
if (root==null)return resList;
LinkedList<TreeNode> q=new LinkedList<>();
q.add(root);
int depth=0;
while (!q.isEmpty()){
resList.add(new ArrayList<>());
int length=q.size();
for (int i=0;i<length;i++){
TreeNode cur=q.remove();
resList.get(depth).add(cur.val);
if (cur.left!=null){
q.add(cur.left);
}
if (cur.right!=null){
q.add(cur.right);
}
}
depth++;
}
return resList;
}