【C++】Morris迭代遍历及代码实现

Morris遍历

传统的借助栈的二叉树迭代遍历需要O(n)级的内存空间,而Morris迭代遍历借助多个结点指针,可以之用O(1)级的内存空间。

二叉树的结构:

struct TreeNode
{
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

前序遍历

思路

1、设置结点指针cur指向当前二叉树的根节点。
2、若cur不为空,则继续,否则退出。
3、若cur结点的左孩子不为空,则找到cur结点左孩子的最右结点,用结点指针pre指向该结点。

  • 若pre结点的右孩子为空,则让pre的右孩子指向cur,输出cur指向结点的值,cur指向cur的左孩子。重回2。
  • 若pre结点的右孩子不为空,则然后将pre的右孩子置空。cur指向其右孩子。重回2。

4、若cur结点的左孩子为空,则输出cur指向结点的值,cur指向cur的右孩子。重回2。

代码实现

vector<int> preorderTraversal(TreeNode *root)
{
     vector<int> res;
     TreeNode *cur = root;
     TreeNode *pre = nullptr;
     while (cur)
     {
          pre = pre->left;
          if (pre)
          {
               while (pre->right && pre->right != cur)
               {
                    pre = pre->right;
               }
               if (!pre->right)
               {
                    pre->right = cur;
                    res.push_back(cur->val);
                    cur = cur->left;
                    continue;
               }
               pre->right = nullptr;
          }
          else
               res.push_back(cur->val);
          cur = cur->right;
     }
     return res;
}

中序遍历

思路

1、设置结点指针cur指向当前二叉树的根节点。
2、若cur不为空,则继续,否则退出。
3、若cur结点的左孩子不为空,则找到cur结点左孩子的最右结点,用结点指针pre指向该结点。

  • 若pre结点的右孩子为空,则让pre的右孩子指向cur,cur指向cur的左孩子。重回2。
  • 若pre结点的右孩子不为空,则然后将pre的右孩子置空。输出cur指向结点的值,cur指向其右孩子。重回2。

4、若cur结点的左孩子为空,则输出cur指向结点的值,cur指向cur的右孩子。重回2。

代码实现

vector<int> inorderTraversal(TreeNode *root)
{
     vector<int> res;
     TreeNode *cur = root;
     TreeNode *pre = nullptr;
     while (cur)
     {
          pre = pre->left;
          if (pre)
          {
               while (pre->right && pre->right != cur)
               {
                    pre = pre->right;
               }
               if (!pre->right)
               {
                    pre->right = cur;
                    cur = cur->left;
                    continue;
               }
               pre->right = nullptr;
          }
          res.push_back(cur->val);
          cur = cur->right;
     }
     return res;
}

后序遍历

思路

1、生成一个新的结点指针cur,其左孩子指向当前二叉树的根节点。
2、若cur不为空,则继续,否则退出。
3、若cur结点的左孩子不为空,则找到cur结点左孩子的最右结点,用结点指针pre指向该结点。

  • 若pre结点的右孩子为空,则让pre的右孩子指向cur,cur指向cur的左孩子。重回2。
  • 若pre结点的右孩子不为空,则然后将pre的右孩子置空。输出cur左孩子到pre结点值的倒序。cur指向其右孩子。重回2。

4、若cur结点的左孩子为空,则cur指向cur的右孩子。重回2。

代码实现

void notePath(vector<int> &res, TreeNode *root)
{
     int count = 0;
     for (; root; ++count)
     {
          res.push_back(root->val);
          root = root->right;
     }
     reverse(res.end() - count, res.end());
}

vector<int> inorderTraversal(TreeNode *root)
{
     vector<int> res;
     TreeNode *cur = new TreeNode();
     cur->left = root;
     TreeNode *pre = nullptr;
     while (cur)
     {
          pre = pre->left;
          if (pre)
          {
               while (pre->right && pre->right != cur)
               {
                    pre = pre->right;
               }
               if (!pre->right)
               {
                    pre->right = cur;
                    cur = cur->left;
                    continue;
               }
               pre->right = nullptr;
               notePath(res, cur->left);
          }
          cur = cur->right;
     }
     return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值