先简单介绍下线索二叉树,线索二叉树不需要额外的空间便可以O(n)遍历二叉树,它充分利用了节点的空指针,若当前结点的左孩子不为空则其左指针指向左孩子结点,否则指向当前节点的前驱;若当前结点的右孩子不为空则其右指针指向右孩子结点,否则指向当前节点的后继。具体看代码实现
前序遍历二叉树:
顺序:中左右
递归:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public void DFS(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
list.add(root.val);
DFS(root.left, list);
DFS(root.right, list);
}
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
DFS(root, list);
return list;
}
}
非递归:先不断往左遍历并记录结点值,然后不断弹栈向右,这时候向右是因为以当前右结点父亲为子树根的子树的子树根和其左子树已经遍历完成。
/**
* 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) {
Stack<TreeNode> stk = new Stack<>();
List<Integer> list = new ArrayList<>();
while(!stk.empty() || root != null) {
while (root != null) {
stk.push(root);
list.add(root.val);
root = root.left;
}
if (!stk.empty()) {
root = stk.peek();
stk.pop();
root = root.right;
}
}
return list;
}
}
非递归非栈:找最右孩子是因为在前序遍历中右子树最后访问,通过pre.right回到cur的条件其实蕴含以cur结点左孩子为根的子树全部遍历完成
/**
* 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> list = new ArrayList<>();
TreeNode cur = root, pre = null;
while(cur != null) {
if (cur.left == null) {
list.add(cur.val);
cur = cur.right;
}
else {
pre = cur.left;
//找cur的前驱结点
while(pre.right != null && pre.right != cur) {
pre = pre.right;
}
//将cur结点置为其前驱结点的右孩子
if (pre.right == null) {
pre.right = cur;
list.add(cur.val);
cur = cur.left;
}
//恢复二叉树
else {
pre.right = null;
cur = cur.right;
}
}
}
return list;
}
}
中序遍历二叉树:
顺序:左中右
递归:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
void DFS(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
DFS(root.left, list);
list.add(root.val);
DFS(root.right, list);
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
DFS(root, list);
return list;
}
}
非递归(栈):和前序遍历不同的地方主要是记录结点值要在已经遍历到最左时记录,因为中序的顺序是左中右
/**
* 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) {
Stack<TreeNode> stk = new Stack<>();
List<Integer> list = new ArrayList<>();
while (root != null || !stk.empty()) {
while (root != null) {
stk.push(root);
root = root.left;
}
if (!stk.empty()) {
root = stk.peek();
stk.pop();
list.add(root.val);
root = root.right;
}
}
return list;
}
}
非递归非栈:可以发现同前序的区别仅在add的时刻不同,因为中序需要先访问最左结点,与前序相同的是右子树最后访问
/**
* 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> list = new ArrayList<>();
TreeNode cur = root, pre = null;
while(cur != null) {
if (cur.left == null) {
list.add(cur.val);
cur = cur.right;
}
else {
pre = cur.left;
//找cur的前驱结点
while(pre.right != null && pre.right != cur) {
pre = pre.right;
}
//将cur结点置为其前驱结点的右孩子
if (pre.right == null) {
pre.right = cur;
cur = cur.left;
}
//恢复二叉树
else {
list.add(cur.val);
cur = cur.right;
pre.right = null;
}
}
}
return list;
}
}
后序遍历二叉树:
顺序:左右中
递归:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
void DFS(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
DFS(root.left, list);
DFS(root.right, list);
list.add(root.val);
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
DFS(root, list);
return list;
}
}
非递归:和上面不同,后续遍历的做法是先将根压栈然后压右节点最后压左结点,当全部压栈完成后,从栈中取出值记录即可,注意非叶子结点需要根据其左右孩子是否访问来确定是否记录
/**
* 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) {
Stack<TreeNode> stk = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode pre = root;
if (root != null) {
stk.push(root);
}
while (!stk.empty()) {
root = stk.peek();
if (root.left == null && root.right == null) {
list.add(root.val);
pre = root;
stk.pop();
continue;
}
if (pre != null && (root.left == pre || root.right == pre)) {
list.add(root.val);
pre = root;
stk.pop();
continue;
}
if (root.right != null) {
stk.push(root.right);
}
if (root.left != null) {
stk.push(root.left);
}
}
return list;
}
}
非递归非栈:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
void reverse(TreeNode from, TreeNode to) {
if (from == to) {
return;
}
TreeNode x = from, y = from.right, z;
while(x != to) {
z = y.right;
y.right = x;
x = y;
y = z;
}
}
void getAns(TreeNode from, TreeNode to, List<Integer> list) {
reverse(from, to);
TreeNode p = to;
while(true) {
list.add(p.val);
if (p == from) {
break;
}
p = p.right;
}
reverse(to, from);
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
TreeNode help = new TreeNode(-1);
help.left = root;
TreeNode cur = help, pre = null;
while(cur != null) {
if (cur.left == null) {
cur = cur.right;
}
else {
pre = cur.left;
//找cur的前驱结点
while(pre.right != null && pre.right != cur) {
pre = pre.right;
}
//将cur结点置为其前驱结点的右孩子
if (pre.right == null) {
pre.right = cur;
cur = cur.left;
}
//恢复二叉树
else {
getAns(cur.left, pre, list);
pre.right = null;
cur = cur.right;
}
}
}
help.left = null;
return list;
}
}