树节点的基本结构:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
1.先序遍历:
遍历顺序:根-左孩子-右孩子
1.1 递归算法:
class Solution {
List res;
public List preorderTraversal(TreeNode root) {
res = new LinkedList();
preTraver(root);
return res;
}
public void preTraver(TreeNode root) {
if(root != null) {
res.add(root.val);
preTraver(root.left);
preTraver(root.right);
}
}
}
1.2 非递归算法:
使用栈来做。最外面用root变量来保存左孩子。root不为空,则直接入栈,并记录下当前值(因为先序遍历是先遍历根);如果root为空,说明此时栈顶结点应该遍历右孩子,则出栈,并遍历右孩子。
class Solution {
List res;
public List preorderTraversal(TreeNode root) {
Deque stack = new LinkedList();
List res = new ArrayList();
while(root!=null || !stack.isEmpty()) {
if(root != null) {
stack.addFirst(root);
res.add(root.val);
root = root.left;
} else {
TreeNode p = stack.pollFirst();
if(p.right != null) {
root = p.right;
}
}
}
return res;
}
}
2.中序遍历
遍历顺序:左孩子-根-右孩子
2.1 递归算法:
使用栈来做。最外面用root变量来保存左孩子。root不为空,则直接入栈;如果root为空,说明此时栈顶结点应该遍历右孩子。
class Solution {
List res;
public List inorderTraversal(TreeNode root) {
res = new ArrayList();
inorderTraver(root);
return res;
}
public void inorderTraver(TreeNode root) {
if(root != null) {
inorderTraver(root.left);
res.add(root.val);
inorderTraver(root.right);
}
}
}
2.2 非递归算法:
使用栈来做。最外面用root变量来保存左孩子。root不为空,则直接入栈;如果root为空,说明此时栈顶结点应该遍历右孩子,则出栈,记录下当前结点的值(因为中序遍历是先遍历左孩子,然后才是根),然后遍历右孩子。
与先序遍历基本相同,唯一不同的地方在于何时记录结点值。先序遍历是入栈的时候记录结点值,中序遍历时出栈的时候记录结点值。
class Solution {
public List inorderTraversal(TreeNode root) {
List res = new ArrayList();
Deque stack = new LinkedList();
while(root!=null || !stack.isEmpty()) {
if(root != null) {
stack.addFirst(root);
root = root.left;
} else {
TreeNode p = stack.poll();
res.add(p.val);
root = p.right;
}
}
return res;
}
}
3. 后序遍历
遍历顺序:左孩子-右孩子-根
3.1 递归算法
class Solution {
List res;
public List postorderTraversal(TreeNode root) {
res = new ArrayList();
posTraver(root);
return res;
}
public void posTraver(TreeNode root) {
if(root != null) {
posTraver(root.left);
posTraver(root.right);
res.add(root.val);
}
}
}
3.2 非递归算法
考虑到,先序遍历是(根-左孩子-右孩子)、后序遍历是(左孩子-右孩子-根)因此可以再先序遍历的基础上进行改进,改成(根-右孩子-左孩子),然后进行逆置操作。对于ArraList可以采用Collections.reverse(res)来进行逆置。
class Solution {
public List postorderTraversal(TreeNode root) {
List res = new ArrayList();
Deque stack = new LinkedList();
while(root != null || !stack.isEmpty()) {
if(root != null) {
stack.addFirst(root);
res.add(root.val);
root = root.right;
} else {
TreeNode p = stack.pollFirst();
root = p.left;
}
}
Collections.reverse(res);
return res;
}
}
4. 层序遍历
4.1 递归算法
记录下当前结点位于第几层,先后遍历左右结点。
class Solution {
List> res;
public List> levelOrder(TreeNode root) {
res = new ArrayList>();
if(root == null) {return res;}
levelTravel(root, 0);
return res;
}
public void levelTravel(TreeNode root, int level) {
if(root == null) {
return ;
}
List temp ;
if(level >= res.size()) {
temp = new ArrayList();
res.add(temp);
} else {
temp = res.get(level);
}
temp.add(root.val);
levelTravel(root.left,level +1);
levelTravel(root.right,level +1);
}
}
4.2 非递归算法
采用队列来做。
class Solution {
public List> levelOrder(TreeNode root) {
List> res = new ArrayList>();
if(root == null) {return res;}
Deque queue = new LinkedList();
queue.addFirst(root);
int n = 1;
while(!queue.isEmpty()) {
n = queue.size();
List temp = new ArrayList();
for(int i = 1; i <= n; i++) {
TreeNode p = queue.pollLast();
temp.add(p.val);
if(p.left != null) {
queue.addFirst(p.left);
}
if(p.right != null) {
queue.addFirst(p.right);
}
}
res.add(temp);
}
return res;
}
}