94. 二叉树的中序遍历

  1. 题目链接

  2. 递归版本很简单,这里就不过多介绍,接下来使用非递归版本,就是使用栈,并且是前、中、后序遍历,统一一套逻辑的非递归的二叉树遍历。

  3. 中序遍历:遍历顺序是,左中右,不能使用递归,那我们就要自己使用栈来保存「现场」。当来到一个节点时,第一次来到,不能够输出,要先将左子树的内容全部得到后,再输出该节点。

    • 所以我们第一次来到一个节点A时,我们要将其压入栈,然后第二次遇到节点A时,就可以输出其内容了。但是,我们压入栈的时候,我们怎么知道是第几次来到该节点?

    • 我们使用特殊的节点,nullptr,来标识,也就是我们第一次压入栈后,再压入nullptr,当我们获得一个nullptr时,我们就知道,下一个节点,是第二次来到了。

    • 第一次遇到一个节点A时,我们要怎么操作?注意我们的顺序是左中右,但是要记住,这是栈,所以压入的顺序应该是「右->中->左」,压入「右」和「左」时,正常压入即可,压入「中」时,要先压入「中」,再压入一个nullptr,标识「中」是第二次来到。

    • 第二次遇到节点A时,可以直接弹出了,因为左子树内容肯定已经处理完毕了,右子树也在第一次遇到节点A的时候,已经处理了。

    • 代码

      class Solution {
      public:
          vector<int> inorderTraversal(TreeNode* root) {
              vector<int> ans;
              if (root == nullptr) {
                  return ans;
              }
              stack<TreeNode*> st;
              st.push(root);    // 第一个节点   不用压入nullptr  因为还不算第一次处理
              while(!st.empty()) {
                  TreeNode *cur = st.top();
                  st.pop();
                  if (cur == nullptr) {   // 栈顶的   就是第二次遇到了  第二次遇到  不需要再入栈了   收集答案即可
                      cur = st.top();
                      st.pop();
                      ans.push_back(cur->val);
                  } else {   // 第一次遇到   中序 左中右   压入顺序就是右中左
                      // 右
                      if (cur->right != nullptr) {
                          st.push(cur->right);
                      }
                      // 中   注意这里不要弄反了
                      st.push(cur);
                      st.push(nullptr);
                      // 左
                      if(cur->left != nullptr) {
                          st.push(cur->left);
                      }
                  }
              }
              return ans;
          }
      };
      
  4. 前序遍历

    • 题目链接

    • 中左右,因为遇到一个节点A,直接得到结果,所以不需要再次入栈了,也就不需要用nullptr来标识了。

    • 代码

      class Solution {
      public:
          vector<int> preorderTraversal(TreeNode* root) {
              vector<int> ans;
              if (root == nullptr) {
                  return ans;
              }
              stack<TreeNode*> st;
              st.push(root);    // 第一个节点   不用压入nullptr  因为还不算第一次处理
              while(!st.empty()) {
                  TreeNode *cur = st.top();
                  st.pop();
                  ans.push_back(cur->val);
                 // 前序,所以是中左右,压入栈就是反过来  右左中,又因为中已经得到结果了所以不用压入栈了 
                  // 右
                  if (cur->right != nullptr) {
                      st.push(cur->right);
                  }
                  // 左
                  if(cur->left != nullptr) {
                      st.push(cur->left);
                  }   
              }
              return ans;
          }
      };
      
  5. 后序遍历

    • 题目链接

    • 左右中,第一次遇到节点A,不能够得到结果,还需要压入栈,所以和中序的套路一样的,用nullptr来标识

    • 代码

      class Solution {
      public:
          vector<int> postorderTraversal(TreeNode* root) {
              vector<int> ans;
              if (root == nullptr) {
                  return ans;
              }
              stack<TreeNode*> st;
              st.push(root);    // 第一个节点   不用压入nullptr  因为还不算第一次处理
              while(!st.empty()) {
                  TreeNode *cur = st.top();
                  st.pop();
                  if (cur == nullptr) {   // 栈顶的   就是第二次遇到了  第二次遇到  不需要再入栈了   收集答案即可
                      cur = st.top();
                      st.pop();
                      ans.push_back(cur->val);
                  } else {   // 第一次遇到   后序 左右中   压入顺序就是中右左
                      // 中   注意这里不要弄反了
                      st.push(cur);
                      st.push(nullptr);
                      // 右
                      if (cur->right != nullptr) {
                          st.push(cur->right);
                      }
                      // 左
                      if(cur->left != nullptr) {
                          st.push(cur->left);
                      }
                  }
              }
              return ans;
          }
      };
      
  6. 三种非递归,代码整体逻辑一摸一样,就是压入栈的时候,顺序不一致

posted @ 2024-11-15 16:09  ouyangxx  阅读(34)  评论(0编辑  收藏  举报