zoukankan      html  css  js  c++  java
  • 深入理解中序遍历二叉树

    起因

    邓俊辉的中序遍历二叉树采用了和前序遍历不同的循环检查方式,在前序遍历时使用stack非空检查,而在中序遍历时采用了while1检查。不便于迁移学习。

    分析

    视频地址:
    https://www.bilibili.com/video/BV1jt4y117KR?p=173
    中序遍历时,根据规律每次进入一颗子树也需要先遍历左侧分支。由于左侧分支的发现顺序和访问顺序是逆序的,因此会想到借助stack来实现。
    当进入一颗子树时,先遍历左侧分支发现节点并push stack,左侧遍历到空节点时,访问栈top节点,(左侧没有节点了,该访问当前根)。左子树为空和左子树访问完都应该访问当前根节点。
    之后,如果有右子树则进入右子树,这里要思考的是右子树的根节点push stack还是直接赋值。
    第一种方案,将右子树根节点push stack.
    因此一开始可能写下这样的代码:

        vector<int> inorderTraversal(TreeNode* root) {
            vector<int> ret;
            if (!root) return ret;
            vector<TreeNode *> stack = {root};
            while (!stack.empty()) {
                auto node = stack.back();
                    while (node->left) {
                        stack.push_back(node->left);
                        node = node->left;
                    }
                node = stack.back();
                ret.push_back(node->val);
                stack.pop_back();
                if (node->right) {
                    stack.push_back(node->right);
                }
            }
            return ret;
    

    但对于[1,null,2,3,null]的树形结构,在push节点2后,stack状态为[2],检查stack非空,进入以2为根的右子树,再开始遍历左侧分支。发现3时,stack为[2,3],访问3且3没有右子树,检查stack非空,又回到以2为根的子树,又开始了左侧分支遍历,循环不能终止。注意:我们这时通过stack非空回到以2为根的子树,开始遍历2的左侧分支。遍历左侧分支这个操作是第一次进入一棵子树(发现根节点)的操作,而不应该是从一个子树根节点的左子树访问完成回来时的操作。
    因此,需要一个从左侧分支返回当前根节点的标志位。
    此外,还应该思考的是,每次检查stack非空的含义是什么?
    比如第一次进入整颗树的时候,要检查一次树的根节点。进入以2为根的子树时,也检查了stack非空。从3访问结束返回2的时候也检查了stack非空。所以,第一次进入一颗树的时候检查了stack的状态,而从左子树返回的时候也检查了stack的状态。这两种条件下,后者不需要遍历左侧分支的操作,因此还是印证了我们的想法:需要一个从左侧分支返回当前根节点的标志位
    因此,改写后的代码如下:

        vector<int> inorderTraversal(TreeNode* root) {
    
            vector<int> ret;
            if (!root) return ret;
            vector<TreeNode *> stack = {root};
            int lefthasvisited= 0;
            while (!stack.empty()) {
                auto node = stack.back();
                if (!lefthasvisited) { // 只有是第一次进入一颗树的时候才进行左侧分支遍历
                    while (node->left) {
                        stack.push_back(node->left);
                        node = node->left;
                    }
                }
                node = stack.back();
                ret.push_back(node->val);
                stack.pop_back();
                lefthasvisited = 1;
                if (node->right) {
                    stack.push_back(node->right);
                    lefthasvisited = 0; // 发现有右子树的时候,需要将左子树访问完成的标志位重置
                }
                    
                
            }
            return ret;
    
  • 相关阅读:
    1094. Car Pooling
    121. Best Time to Buy and Sell Stock
    58. Length of Last Word
    510. Inorder Successor in BST II
    198. House Robber
    57. Insert Interval
    15. 3Sum java solutions
    79. Word Search java solutions
    80. Remove Duplicates from Sorted Array II java solutions
    34. Search for a Range java solutions
  • 原文地址:https://www.cnblogs.com/ijpq/p/15456974.html
Copyright © 2011-2022 走看看