前序遍历
非递归
从根节点开始,每次迭代弹出当前栈顶元素访问,并将其孩子节点压入栈中,先压右孩子再压左孩子(入栈是逆序的,从而出栈为先左后右,再加上最开始的根节点,就是根左右)。
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null)
return res;
Stack<TreeNode> st = new Stack<TreeNode>();
st.push(root);
while(!st.isEmpty()){
TreeNode c = st.pop();
res.add(c.val);
if(c.right != null){
st.push(c.right);
}
if(c.left != null){
st.push(c.left);
}
}
return res;
}
中序遍历
非递归
1、若当前节点不为空,则压栈,然后向左子节点走2、当前节点为空,则出栈,访问,然后想这个节点的右子节点走
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
后序遍历
非递归
方法1
由于后续是“左右根”,后前序为“根左右”,那只需要把前序改成“根右左”,再将结果置逆就得到了“左右根”,然后返回即可。
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
Stack<TreeNode> st = new Stack<>();
st.push(root);
while (!st.isEmpty()){
TreeNode c = st.pop();
res.add(c.val);//与前序唯一区别就是子节点压栈次序改变
if(c.left != null){
st.push(c.left);
}
if(c.right != null){
st.push(c.right);
}
}
Collections.reverse(res);
return res;
}
方法2
有一个last节点,记录右子树是否被访问过,整体思路和中序遍历比较像,先一直往左走,不断入栈,再判断最后一个节点,是否有右子树,或者右子树是否已经被访问过,关键在于这个last节点,用于判断右字数是否已被访问。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null){
return res;
}
Stack<TreeNode> st = new Stack<>();
TreeNode c = root,last = null;
while(c != null || !st.isEmpty()){
while(c != null){
st.push(c);
c = c.left;
}
c = st.peek();
if(c.right == null || c.right == last){
last = st.pop();
res.add(c.val);
c = null;
}else{
c = c.right;
}
}
return res;
}
}
二叉树的层次遍历
leetcode 面试题32 - I. 从上到下打印二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
List<Integer> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
if(root != null){
queue.add(root);
}
while(!queue.isEmpty()){
TreeNode node = queue.poll();
res.add(node.val);
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
}
int[] arr = new int[res.size()];
for(int i=0; i<res.size(); i++) {
arr[i] = res.get(i);
}
return arr;
}
}
从前序与中序遍历序列构造二叉树
Leetcode105
递归解法
关键在于找到每个子树的边界
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder == null || preorder.length == 0)
return null;
map = new HashMap<>();//优化查找速度
for(int i = 0;i < preorder.length;i++){
map.put(inorder[i],i);
}
return generate(preorder,0,preorder.length - 1,inorder,0,inorder.length - 1);
}
HashMap<Integer,Integer> map;
public TreeNode generate(int[] preorder,int preStart,int preEnd, int[] inorder,int inStart,int inEnd){
if(preStart > preEnd || inStart > inEnd)
return null;
TreeNode c = new TreeNode(preorder[preStart]);
int inIndex = map.get(c.val);
c.left = generate(preorder,preStart + 1,preStart + inIndex - inStart,inorder,inStart,inIndex - 1);
c.right = generate(preorder,preStart + inIndex - inStart + 1,preEnd,inorder,inIndex + 1,inEnd);
return c;
}
}