赞
踩
首先树的遍历分为,前序遍历,中序遍历,后序遍历。
前序遍历: 对于当前结点,先对该结点进行操作,然后对他的左孩子进行操作,最后对他的右孩子进行操作。
中序遍历: 对于当前结点,先对该结点的左孩子进行操作,然后对该结点进行操作,最后对他的右孩子进行操作。
后序遍历: 对于当前结点,先对该结点的左结点进行操作,然后对右孩子进行操作,最后多该结点进行操作。
递归序:
其实对于树的遍历,递归法实现是比较简单的,只需要调整递归函数调用的位置即可,可是为什么递归能实现前序遍历,中序遍历和后序遍历呢?实际上是由递归时访问结点的顺序决定的。
public void recur(Node head){
if(head == null) return;
// 1
recur(head.left);
// 2
recur(head.right);
// 3
}
以上为递归遍历树时的通用代码,我们发现,对于当前结点head,在当前这个recur中,其实有三次都会返回到该结点,如注释1,这时当前结点为head结点;对于注释2,由于调用recur(head.left)结束,会再次返回到该结点;对于注释3,由于调用recur(head.right)结束,会再次返回到该结点,因此总共有三次会访问同一结点。
对于该树,递归序为,1,2,4,4,4,2,5,5,5,2,1,3,6,6,6,3,7,7,7,3,1。
因此前序中序后序遍历,就是在分别在第一次第二次第三次到达该结点时进行操作,例如,前序遍历则是在1时,此时是第一次访问到该结点,因此先对该结点进行操作,就可以实现先序遍历。知道了递归序,递归实现树的三种遍历就很容易了,代码如下:
先序遍历:
public void preOrderRecur(Node head){
if(head == null) return;
System.out.print(head.val);
recur(head.left);
recur(head.right);
}
中序遍历:
public void inOrderRecur(Node head){
if(head == null) return;
recur(head.left);
System.out.print(head.val);
recur(head.right);
}
后序遍历:
public void posOrderRecur(Node head){
if(head == null) return;
recur(head.left);
recur(head.right);
System.out.print(head.val);
}
两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同。
先序遍历迭代法
首先我们可以先定义一个栈,然后重复进行一下操作:
// 先序遍历! class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); if (root == null){ return res; } Deque<TreeNode> stack = new LinkedList<TreeNode>(); if(root != null){ stack.push(root); } while(root != null && !stack.isEmpty() ){ root = stack.pop(); //要注意弹出的不能为null,因此循环中需要判断stack不为空 res.add(root.val); // 弹出后进行操作。 if(root.right != null){ stack.push(root.right); } if(root.left != null){ stack.push(root.left); } } return res; } }
中序遍历迭代法:
即一直向左遍历,并且在遍历途中先将根结点和压入栈中,然后弹出左叶子结点后先判断是否其存在右结点(左结点在循环中已经判断),如果不存在则将其根结点进行弹出并输出,若存在,则继续向该右结点重复上述向左遍历的操作。
public static void inOrderUnRecur(Node root) { System.out.print("in-order: "); if (root != null) { Deque<TreeNode> stack = new LinkedList<TreeNode>(); while (!stack.isEmpty() || root != null) { if (root != null) { stack.push(root); root = root.left; } else { root = stack.pop(); System.out.print(root.value + " "); root = root.right; } } } System.out.println(); }
后序遍历迭代法
对于后序遍历,在树的知识点与算法中给出了一种遍历方法,但是可能会比较难理解,因此这里给出第二种方法。
首先由于根节点需要最后访问,而找到它的左右结点一定要先经过根结点,因此需要两个栈来维护访问顺序。栈1为访问所有结点的中介栈,栈2为最终所有结点的收集栈。我们要通过栈1实现压入栈2的顺序为头右左,这样在栈2中打印出来的顺序则可以变为左右头,实现后序遍历。
public void posOrderUnrecur(TreeNode root){ if(root!=null){ Deque<TreeNode> s1 = new LinkedList<TreeNode>(); // 中介栈 Deque<TreeNode> s1 = new LinkedList<TreeNode>(); // 收集栈 s1.push(root); while(!s1.isEmpty()){ root = s1.pop(); s2.push(root); if(root.left != null){ s1.push(root.left); // 先放左 } if(root.right != null){ s1.push(root.right); // 后方右 } } while(!s2.isEmpty()){ System.out.print(s2.pop().val); } } }
如有错误,请大家指出,大家一起进步。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。