四种遍历树的算:前序、中序、后序、层次遍历(正向,反向,Z字形遍历)
遍历二叉树算法基本操作是访问结点,不论按哪一种次序进行遍历,对含n个结点的二叉树时间复杂度都为O(n)。
前序遍历:
递归方式:
void preorder_recursive(Bitree T) /* 先序遍历二叉树的递归算法 */
{
if (T) {
visit(T); /* 访问当前结点 */
preorder_recursive(T->lchild); /* 访问左子树 */
preorder_recursive(T->rchild); /* 访问右子树 */
}
}
非递归方式:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<Integer>();
Stack<TreeNode> s=new Stack<TreeNode>();
if(root==null)return res;
s.push(root);
while(!s.empty()){
TreeNode node=s.pop();
res.add(node.val);
if(node.right!=null){
s.push(node.right);
}
if(node.left!=null){
s.push(node.left);
}
}
return res;
}
}
这里注意到:一开始就是将栈顶元素出栈,并先将右节点再将左节点放入栈中(之间是if...if关系,不是if...else关系,因为左右节点的父节点已经出栈了,一定要一次性将左右入栈,否则后面无法再入)
不能写成下面这样,否则死循环:
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<Integer>();
Stack<TreeNode> s=new Stack<TreeNode>();
if(root==null)return res;
s.push(root);
res.add(root.val);
while(!s.empty()){
TreeNode node=s.peek();
if(node.left==null&&node.right==null){
s.pop();
}else if(node.left!=null){
res.add(node.left.val);
s.push(node.left);
}else if(node.right!=null){
res.add(node.right.val);
s.push(node.right);
}
}
return res;
}
}
中序遍历
递归方式
void inorder_recursive(Bitree T) /* 中序遍历二叉树的递归算法 */
{
if (T) {
inorder_recursive(T->lchild); /* 访问左子树 */
visit(T); /* 访问当前结点 */
inorder_recursive(T->rchild); /* 访问右子树 */
}
}
非递归方式
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<Integer>();
Stack<TreeNode> stack=new Stack<TreeNode>();
if(root==null)return res;
TreeNode node=root;
while(node!=null||!stack.empty()){
if(node != null){
stack.push(node);
node = node.left;
}else{
node = stack.pop();
res.add(node.val);
node = node.right;
}
}
return res;
}
}
后序遍历:
递归方式:
void postorder_recursive(Bitree T) /* 中序遍历二叉树的递归算法 */
{
if (T) {
postorder_recursive(T->lchild); /* 访问左子树 */
postorder_recursive(T->rchild); /* 访问右子树 */
visit(T); /* 访问当前结点 */
}
}
非递归方式
可以修改原树:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<Integer>();
if(root==null) return res;
Stack<TreeNode> sta=new Stack<TreeNode>();
sta.push(root);
while(!sta.empty()) {
TreeNode top = sta.peek();
if(top.left!=null) {
sta.push(top.left);
top.left = null;
} else if(top.right!=null) {
sta.push(top.right);
top.right = null;
} else {
sta.pop();
res.add(top.val);
}
}
return res;
}
}
不可修改原树:
算法如下:
1)如果根节点非空,将根节点加入到栈中。
2)如果栈不空,取栈顶元素(暂时不弹出),
如果(左子树已访问过或者左子树为空),且(右子树已访问过或右子树为空),则弹出栈顶节点,将其值加入数组,并进行第三步。
如果左子树不为空,切未访问过,则将左子节点加入栈中,并标左子树已访问过。并进行第三步(不继续判断右子树,这是关键)。
如果右子树不为空,切未访问过,则将右子节点加入栈中,并标右子树已访问过。并进行第三步。
3)重复第二步,直到栈空。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class TreeNodeWrapped {
TreeNode node;
boolean isLeftVisit=false;
boolean isRightVisit=false;
TreeNodeWrapped(TreeNode node) {
this.node=node;
}
}
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<Integer>();
if(root==null) return res;
Stack<TreeNodeWrapped> stack=new Stack<TreeNodeWrapped>();
TreeNodeWrapped rootWrapped=new TreeNodeWrapped(root);
stack.push(rootWrapped);
while(!stack.empty()) {
TreeNodeWrapped top = stack.peek();
if((top.node.left==null||top.isLeftVisit==true)&&(top.node.right==null||top.isRightVisit==true)){
res.add(top.node.val);
stack.pop();
}else{
if(top.node.left!=null&&top.isLeftVisit==false){
stack.push(new TreeNodeWrapped(top.node.left));
top.isLeftVisit=true;
}else if(top.node.right!=null&&top.isRightVisit==false){
stack.push(new TreeNodeWrapped(top.node.right));
top.isRightVisit=true;
}
}
}
return res;
}
}
层次遍历
用一个队列
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
public class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<List<Integer>>();
LinkedBlockingQueue queue=new LinkedBlockingQueue();
if(root==null)return res;
queue.add(root);
int count=1;
while(!queue.isEmpty()){
int count2=0;
List<Integer> temp=new ArrayList<Integer>();
while(count>0&&!queue.isEmpty()){
TreeNode head=(TreeNode) queue.poll();
temp.add(head.val);
if(head.left!=null){
queue.add(head.left);
count2++;
}
if(head.right!=null){
queue.add(head.right);
count2++;
}
count--;
}
count=count2;
res.add(temp);
}
return res;
}
}
递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.ArrayList;
import java.util.List;
public class Solution {
List<List<Integer>> res=null;
public List<List<Integer>> levelOrder(TreeNode root) {
res=new ArrayList<List<Integer>>();
func(root,0);
return res;
}
void func(TreeNode node,int level){
if(node==null)return;
if(res.size()==level){
res.add(new ArrayList<Integer>());
}
res.get(level).add(node.val);
func(node.left,level+1);
func(node.right,level+1);
}
}
反向层次遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
LinkedList<List<Integer>> list = new LinkedList<List<Integer>>();
addLevel(list, 0, root);
return list;
}
private void addLevel(LinkedList<List<Integer>> list, int level, TreeNode node) {
if (node == null) return;
if (list.size()-1 < level) list.addFirst(new LinkedList<Integer>());
list.get(list.size()-1-level).add(node.val);
addLevel(list, level+1, node.left);
addLevel(list, level+1, node.right);
}
}
这里注意:用 LinkedList而不用ArrayList,是因为list.addFirst,list.add会快一点,但list.size(),list.get会慢
分层Z字形遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new LinkedList<>();
if (root == null) {
return result;
}
// 遍历标志,0表示从左到右,1表示从右到左
int flag = 0;
TreeNode node;
// 记录每一层的元素
List<Integer> lay = new LinkedList<>();
// 双向队列,当作栈来使用,记录当前层待处理结点
Deque<TreeNode> stack = new LinkedList<>();
// 记录下一层待处理结点
Deque<TreeNode> nextStack = new LinkedList<>();
stack.add(root);
while (!stack.isEmpty()) {
// 删除栈顶元素
node = stack.removeLast();
// 结果入队
lay.add(node.val);
// 如果当前是从左到右遍历,按左子树右子树的顺序添加
if (flag == 0) {
if (node.left != null) {
nextStack.addLast(node.left);
}
if (node.right != null) {
nextStack.addLast(node.right);
}
}else {// 如果当前是从右到左遍历,按右子树左子树的顺序添加
if (node.right != null) {
nextStack.addLast(node.right);
}
if (node.left != null) {
nextStack.addLast(node.left);
}
}
// 当前层已经处理完了
if (stack.isEmpty()) {
Deque<TreeNode> temp = nextStack;
nextStack = stack;
stack = temp;
// 标记下一层处理的方向
flag = 1 - flag;
// 保存本层结果
result.add(lay);
// 创建新的链表处理下一层的结果
lay = new LinkedList<>();
}
}
return result;
}
}