递归遍历
前序遍历(中左右)
写递归的三件事情确认:
1.递归结束条件
2.递归的参数和返回值
3.每次递归的操作
对于二叉树的遍历,递归的条件是root结点为空,那么就返回。递归传的参数,就是每次需要一个根节点和一个结果数组。每次递归的时候递归的使用这个递归方法,让root结点的左右孩子作为下一个root结点进行遍历,直到root的孩子为空就返回。中序遍历和后续遍历只需调整顺序即可。
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preorder(root, result);// 前序遍历方法,并将root的qianxu0遍历结果保存在result当中
return result;
}
public void preorder(TreeNode root, List<Integer> result) {
if (root == null)
return;// 终止条件
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inorder(root, result);
return result;
}
public void inorder(TreeNode root, List<Integer> result) {
if (root == null)
return;
inorder(root.left, result);
result.add(root.val);
inorder(root.right, result);
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postorder(root, result);
return result;
}
public void postorder(TreeNode root, List<Integer> result) {
if (root == null)
return;
postorder(root.left, result);
postorder(root.right, result);
result.add(root.val);
}
}
迭代遍历
前序遍历(中左右)
迭代遍历和递归遍历的区别是,迭代遍历是使用栈这种数据结构来对模仿二叉树的遍历操作的。对于栈这种“后进先出”的结构,每次将根节点入栈,并且存入结果数组。对于栈这种特殊的数据结构,要先放根节点的右孩子,然后再放左孩子,这样弹出栈顶元素时才能将左孩子弹出来。然后每次都是弹出栈顶元素。
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
// 运用非递归算法实现,用栈这种数据结构来实现
List<Integer> result = new ArrayList<Integer>();
if (root == null)
return result;// 特例情况
Stack<TreeNode> t = new Stack<>();
t.push(root);
while (!t.isEmpty()) {
TreeNode node = t.pop();
result.add(node.val);
if (node.right != null)// 由于是栈操作,先放右孩子,再放左孩子
t.push(node.right);
if (node.left != null)
t.push(node.left);
}
return result;
}
}
后序遍历(左右根)
后序遍历就是让前序遍历(根左右)的左右调换为(根右左),然后反转结果数组即可
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
if (root == null)
return result;
Stack<TreeNode> t = new Stack<>();
t.push(root);// 先将根节点放进栈中
while (!t.isEmpty()) {
TreeNode tr = t.pop();
result.add(tr.val);
if (tr.left != null)
t.push(tr.left);
if (tr.right != null)
t.push(tr.right);
}
Collections.reverse(result);
return result;
}
}
中序遍历(左根右)
中序遍历和前序遍历不同,因为前序遍历的根左右,每次遍历到根后,直接将根的值放进结果数组了,但是对于中序遍历,需要一直找到最左的孩子,然后才开始往结果数组里面填数。所以指针和结果数组不是同步执行的。那么在栈内可以放每次遍历的左孩子,并由cur指针指向这个左孩子,当cur为空的时候,没有左孩子了,那么就可以开始往结果数组里面填数了,填的就是让栈里面弹出一个元素的值,此时的cur指向这个元素,然后让cur去遍历它的右子树。右子树也是一样的,也是要遍历它的左孩子。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
// 左中右的遍历会导致遍历和处理的数字不一样,所以使用指针来访问
List<Integer> result = new ArrayList<>();
if (root == null)
return result;
// 栈里面放节点
Stack<TreeNode> t = new Stack<>();
TreeNode cur = root;
while (cur != null || !t.isEmpty()) {
if (cur != null) {
t.push(cur);
cur = cur.left;
} else {
// 当前节点为空必须弹出一个栈里的元素
cur = t.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}