1. 递归法

递归的三大要素

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

    1.1 前序遍历

    ```java public class PreorderTraversal { ArrayList preOrderReverse(TreeNode root) {

    1. ArrayList<Integer> integers = new ArrayList<>();
    2. preOrder(root,integers);
    3. return integers;

    }

    void preOrder(TreeNode root , ArrayList arrayList) {

    1. //递归的中止条件
    2. if (root == null) {
    3. return;
    4. }
    5. //先序遍历在上面 中序在中间 下序在下面
    6. arrayList.add(root.val);
    7. //依次递归调用左子树 左子树接着遍历
    8. preOrder(root.left, arrayList);
    9. //左子树遍历完 遍历右子树
    10. preOrder(root.right, arrayList);

    } }

  1. 中序后序改变add的位置即可
  2. <a name="PgJyF"></a>
  3. # 2. 迭代法
  4. <a name="DHr17"></a>
  5. ## 2.1 前序遍历
  6. 前序遍历输出顺序为 -> -> 压入顺序为 -> ->
  7. ```java
  8. public class IterationPreorderTraversal {
  9. public List<Integer> preorderTraversal(TreeNode root) {
  10. ArrayList<Integer> res = new ArrayList<>();
  11. if (root == null) {
  12. return res;
  13. }
  14. Stack<TreeNode> stack = new Stack<>();
  15. //栈首先push进root
  16. stack.push(root);
  17. //如果栈不为空就循环
  18. while (!stack.isEmpty()) {
  19. //干了两件事情 1 将栈顶弹出 2将弹出的值赋给了temp
  20. TreeNode temp = stack.pop();
  21. //将弹出的temp的值放到res队列中
  22. res.add(temp.val);
  23. //如果temp的右子节点不为空 就将它push入栈 之所以要先右边是因为弹出的时候先弹出左边
  24. if (temp.right != null) {
  25. stack.push(temp.right);
  26. }
  27. //左边同理 如果父节点的两个子节点都不为空 先弹出的是左节点 左节点弹出后 这时temp变成了左节点 直到左子树遍历完才遍历当前的右子树
  28. if (temp.left != null) {
  29. stack.push(temp.left);
  30. }
  31. }
  32. return res;
  33. }
  34. }

2.2 中序遍历

  1. class Solution {
  2. public List<Integer> inorderTraversal(TreeNode root) {
  3. ArrayList<Integer> res = new ArrayList<>();
  4. if (root == null) {
  5. return res;
  6. }
  7. Stack<TreeNode> stack = new Stack<>();
  8. TreeNode temp = root;
  9. //当栈不等于空(当左子树和根节点都遍历完的时候栈等于空 这时还有右子树没有遍历 就需要在判断树节点不等于空) 树节点不等于空的时候
  10. while (!stack.isEmpty() || temp != null) {
  11. //如果树节点不等于空就将当前节点push入栈 再使当前节点为当前节点的左子节点直到到了最左边为空
  12. if (temp != null) {
  13. stack.push(temp);
  14. temp = temp.left;
  15. } else {
  16. //temp为空代表没有左子树 将当前栈顶弹出 并赋给temp 将temp加到res中
  17. temp = stack.pop();
  18. res.add(temp.val);
  19. //temp往右子树遍历
  20. temp = temp.right;
  21. }
  22. }
  23. return res;
  24. }
  25. }

008eGmZEly1gnbmuj244bg30eq0d4kjm.gif

2.3 后序遍历

  1. class Solution {
  2. public List<Integer> postorderTraversal(TreeNode root) {
  3. ArrayList<Integer> res = new ArrayList<>();
  4. if (root == null) {
  5. return res;
  6. }
  7. Stack<TreeNode> stack = new Stack<>();
  8. stack.push(root);
  9. while (!stack.isEmpty()) {
  10. TreeNode temp = stack.pop();
  11. res.add(temp.val);
  12. if (temp.left != null) {
  13. stack.push(temp.left);
  14. }
  15. if (temp.right != null) {
  16. stack.push(temp.right);
  17. }
  18. }
  19. Collections.reverse(res);
  20. return res;
  21. }
  22. }

image.png

3. 迭代法的统一遍历方法

3.1 前序遍历

  1. class Solution {
  2. public List<Integer> preorderTraversal(TreeNode root) {
  3. ArrayList<Integer> res = new ArrayList<>();
  4. Stack<TreeNode> stack = new Stack<>();
  5. if (root != null) {
  6. stack.push(root);
  7. }
  8. while (!stack.isEmpty()) {
  9. TreeNode node = stack.peek();
  10. if (node != null) {
  11. stack.pop();
  12. if (node.right != null) {
  13. stack.push(node.right);
  14. }
  15. if (node.left != null) {
  16. stack.push(node.left);
  17. }
  18. stack.push(node);
  19. stack.push(null);
  20. } else {
  21. stack.pop();
  22. node = stack.peek();
  23. stack.pop();
  24. res.add(node.val);
  25. }
  26. }
  27. return res;
  28. }
  29. }

压入顺序 右左中

3.2 中序遍历

  1. class Solution {
  2. public List<Integer> inorderTraversal(TreeNode root) {
  3. //返回结果
  4. ArrayList<Integer> res = new ArrayList<>();
  5. Stack<TreeNode> stack = new Stack<>();
  6. //如果根节点!=null就push
  7. if (root!=null) {
  8. stack.push(root);
  9. }
  10. //循环 直到栈=null
  11. while (!stack.isEmpty()) {
  12. //peek栈 得到栈顶元素
  13. TreeNode node = stack.peek();
  14. //如果栈顶!=null 就将栈顶弹出 并且按照右中左的顺序放入栈 压入中间的时候需要再压入一个null
  15. if (node != null) {
  16. stack.pop();// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
  17. if (node.right != null) {
  18. stack.push(node.right);
  19. }
  20. stack.push(node);
  21. stack.push(null);// 中节点访问过,但是还没有处理,加入空节点做为标记。
  22. if (node.left != null) {
  23. stack.push(node.left);
  24. }
  25. } else {// 只有遇到空节点的时候,才将下一个节点放进结果集
  26. stack.pop(); //弹出空节点
  27. node = stack.peek();
  28. stack.pop();
  29. res.add(node.val);
  30. }
  31. }
  32. return res;
  33. }
  34. }

压入顺序 右中左

3.3 后序遍历

  1. class Solution {
  2. public List<Integer> inorderTraversal(TreeNode root) {
  3. //返回结果
  4. ArrayList<Integer> res = new ArrayList<>();
  5. Stack<TreeNode> stack = new Stack<>();
  6. //如果根节点!=null就push
  7. if (root!=null) {
  8. stack.push(root);
  9. }
  10. //循环 直到栈=null
  11. while (!stack.isEmpty()) {
  12. //peek栈 得到栈顶元素
  13. TreeNode node = stack.peek();
  14. //如果栈顶!=null 就将栈顶弹出 并且按照右中左的顺序放入栈 压入中间的时候需要再压入一个null
  15. if (node != null) {
  16. stack.pop();// 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
  17. stack.push(node);
  18. stack.push(null);// 中节点访问过,但是还没有处理,加入空节点做为标记。
  19. if (node.right != null) {
  20. stack.push(node.right);
  21. }
  22. if (node.left != null) {
  23. stack.push(node.left);
  24. }
  25. } else {// 只有遇到空节点的时候,才将下一个节点放进结果集
  26. stack.pop(); //弹出空节点
  27. node = stack.peek();
  28. stack.pop();
  29. res.add(node.val);
  30. }
  31. }
  32. return res;
  33. }
  34. }

后序遍历 中右左