不同叫法指的是父结点在前中后出现,其它结点从左到右出现。

  • 前序
  • 中序
  • 后序

image.png

:::info 递归和迭代的异同:

  • 递归是在查找同时处理(压入输出数组)了,
  • 迭代是经过一个缓存器,把查找的结果边保存边处理 :::

    统一递归法

    递归三部曲

    找到算法的最终结构,或者数学上的表达式,就好设计递归架构。

    1、确定参数、返回值

    2、确定终止条件

    3、确定单层递归的逻辑

    递归代码

    可以认为每一层迭代都可以确定三个元素,其他子元素在下一层进行插缝。 从下面的分析图可以看出,递归需要有自相似性

前序遍历

  1. class Solution {
  2. public:
  3. void traversal(TreeNode* cur, vector<int>& vec) {
  4. if (cur == NULL) return;
  5. vec.push_back(cur->val); // 中
  6. traversal(cur->left, vec); // 左
  7. traversal(cur->right, vec); // 右
  8. }
  9. vector<int> preorderTraversal(TreeNode* root) {
  10. vector<int> result;
  11. traversal(root, result);
  12. return result;
  13. }
  14. };

深度优先算法 - 图2

中序遍历

  1. void traversal(TreeNode* cur, vector<int>& vec) {
  2. if (cur == NULL) return;
  3. traversal(cur->left, vec); // 左
  4. vec.push_back(cur->val); // 中
  5. traversal(cur->right, vec); // 右
  6. }

深度优先算法 - 图3

后序遍历

  1. void traversal(TreeNode* cur, vector<int>& vec) {
  2. if (cur == NULL) return;
  3. traversal(cur->left, vec); // 左
  4. traversal(cur->right, vec); // 右
  5. vec.push_back(cur->val); // 中
  6. }

深度优先算法 - 图4

统一迭代法

注意栈是先进后出,所以压入顺序得反着来

以中序为例:

  1. class Solution {
  2. public:
  3. vector<int> inorderTraversal(TreeNode* root) {
  4. stack<TreeNode*> st; // 缓冲器,用来保存从输入获取的节点
  5. vector<int> result; //结果储存数组
  6. if(root!=nullptr)//如果不为空则压入缓冲器,空则什么都不做,之后只要判断缓冲器是否为空
  7. st.push(root);
  8. while(!st.empty()){ //开始循环更新缓冲器和结果数组
  9. TreeNode *node = st.top(); //首先取出栈顶元素,保存到临时变量
  10. st.pop();//取完要记得弹出
  11. if(node!=nullptr){ //非空则进行访问,更新缓冲器。
  12. if(node->right)
  13. st.push(node->right); //right node因为是stack,所以要先右再左
  14. st.push(node); // middle node
  15. // 🎃中节点已经被访问过,但是还没处理,所以用空节点标记,不再访问直接处理
  16. st.push(nullptr);
  17. if (node->left) //left node
  18. st.push(node->left);
  19. }else{ //空则进行处理,更新结果数组,取空结点后一位,移入结果中
  20. st.pop(); //弹出空结点
  21. node = st.top(); //取出栈中元素
  22. st.pop();
  23. result.push_back(node->val); //压入结果数组中
  24. }
  25. }
  26. return result;
  27. }
  28. };

深度优先算法 - 图5

要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。
动画中,result数组就是最终结果集。
可以看出我们将访问的节点直接加入到栈中,但如果是处理的节点则后面放入一个空节点, 这样只有空节点弹出的时候,才将下一个节点放进结果集。

因为是栈,所以下面顺序都是反的

前序

  1. if (node != NULL) {
  2. if (node->right) st.push(node->right); // 右
  3. if (node->left) st.push(node->left); // 左
  4. st.push(node); st.push(NULL);
  5. }

后序

  1. if (node != NULL) {
  2. st.push(node); st.push(NULL);
  3. if (node->right) st.push(node->right); // 右
  4. if (node->left) st.push(node->left); // 左
  5. }
  1. vetor<int> inorderTraversal(TreeNode* root){
  2. vector<int> result;
  3. stack<TreeNode*> st;
  4. if(root!=nullptr) st.push(root);
  5. while(!st.empty()){
  6. TreeNode* node = st.top();
  7. st.pop();
  8. if(node!=nullptr){
  9. if(node->right) st.push(node->right);
  10. st.push(node); st.push(nullptr);
  11. if(node->left) st.push(node->left);
  12. }else{
  13. st.pop(); //pop NULL
  14. node = st.top();
  15. st.pop();
  16. result.push_back(node->val);
  17. }
  18. }
  19. return result;
  20. }