144.94.145.二叉树的前中后序遍历
递归做法:
递归做法三种遍历方式的区别只在于语句执行顺序,比较好理解这里不过多赘述。
// 前序
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> ans = new ArrayList<>();
preorder(root,ans);
return ans;
}
void preorder(TreeNode root, List<Integer> list){
if(root == null){
return;
}
// 先序: 中左右
list.add(root.val);
preorder(root.left, list);
preorder(root.right, list);
}
}
// 中序
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> ans = new ArrayList<>();
inorder(root,ans);
return ans;
}
void inorder(TreeNode root, List<Integer> list){
if(root == null){
return;
}
// 中序遍历顺序 左中右
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
// 后序
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> ans = new ArrayList<>();
postorder(root,ans);
return ans;
}
void postorder(TreeNode root, List<Integer> list){
if(root == null){
return;
}
// 后序顺序 左右中
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val);
}
}
迭代做法:
迭代解法中前序遍历较为简单,后续遍历是使用前序遍历的巧解
中序遍历的迭代思想就是,将所有左孩子都放到栈中,在处理每一个栈中节点的时候,这个节点必定没有左孩子或者左孩子已经在之前处理过了。所以只需要先输出其本身,再处理其右节点即可。
// 前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> arrayList = new ArrayList<>();
if(root == null) return arrayList;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
// 从根节点开始,从栈中拿出一个节点,将他放入栈,然后将他的右节点和左节点插入
while(!stk.isEmpty()){
TreeNode node = stk.peek();
stk.pop();
arrayList.add(node.val);
// 必须先右后左,因为栈是先进后出
if(node.right != null) stk.push(node.right);
if(node.left != null) stk.push(node.left);
}
return arrayList;
}
}
// 中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> arrayList = new ArrayList<>();
Stack<TreeNode> stk = new Stack<>();
TreeNode cur = root;
while(cur != null || !stk.isEmpty()){
// 中序遍历 左中右
if(cur != null){ // 如果有左孩子,就一直往下走
stk.push(cur);
cur = cur.left;
}else { // 没有左孩子了,就去栈中找没有处理过的左孩子节点
cur = stk.peek(); // 当前节点要么没有左孩子要么左孩子的节点已经处理过了
stk.pop();
arrayList.add(cur.val); // 左已经输出了,所以该输出中了
cur = cur.right; // 将右节点作为跟节点,继续迭代处理。
}
}
return arrayList;
}
}
// 后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// 后序遍历是先序遍历的一种巧解,后序遍历 左右中 先序遍历 中左右
// 先序遍历略微处理就是 中右左 在将结果反转,即是后续遍历
ArrayList<Integer> arrayList = new ArrayList<>();
if(root == null) return arrayList;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
stk.pop();
arrayList.add(cur.val);
if(cur.left != null) stk.push(cur.left);
if(cur.right != null) stk.push(cur.right);
}
Collections.reverse(arrayList);
return arrayList;
}
}
统一迭代法:
不管是前序中序后序,都可以采用统一迭代法对其进行处理:
统一迭代法中的入栈顺序在代码中从下向上看,正是对应遍历方式的遍历顺序
前: 中左右 中: 左中右 后: 左右中
在中间节点再次入栈之后再插入一个null,表示下一次读到它就可以弹出了。
// 前序
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> arrayList = new ArrayList<>();
if(root == null) return arrayList;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
if(cur != null){
stk.pop();
if(cur.right != null) stk.push(cur.right); // 右
if(cur.left != null) stk.push(cur.left); // 左
stk.push(cur); // 中
stk.push(null);
}else{
stk.pop();
arrayList.add(stk.pop().val);
}
}
return arrayList;
}
}
// 中序
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> arrayList = new ArrayList<>();
if(root == null) return arrayList;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
if(cur != null){
stk.pop();
if(cur.right != null) stk.push(cur.right); // 右
stk.push(cur); // 中
stk.push(null);
if(cur.left != null) stk.push(cur.left); // 左
}else{
stk.pop();
arrayList.add(stk.pop().val);
}
}
return arrayList;
}
}
// 后序
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> arrayList = new ArrayList<>();
if(root == null) return arrayList;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
if(cur != null){
stk.pop();
stk.push(cur); // 中
stk.push(null);
if(cur.right != null) stk.push(cur.right); // 右
if(cur.left != null) stk.push(cur.left); // 左
}else{
stk.pop();
arrayList.add(stk.pop().val);
}
}
return arrayList;
}
}