树的遍历方式汇总

如何遍历一棵树

有两种通用的遍历树的策略:

深度优先搜索(DFS)

在这个策略中,我们采用深度作为优先级,以便从跟开始一直到达某个确定的叶子,然后再返回根到达另一个分支。

深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为先序遍历,中序遍历和后序遍历

宽度优先搜索(BFS)

我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到。

下图中的顶点按照访问的顺序编号,按照 1-2-3-4-5 的顺序来比较不同的策略。

 

 

 本问题就是用宽度优先搜索遍历来划分层次:[[1], [2, 3], [4, 5]]

定义树的结点为:

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

(1)二叉树的前序遍历

 方法1:递归

class Solution {
public:
    vector<int>res;
    vector<int> preorderTraversal(TreeNode* root) {
        if(root==NULL)
            return res;
        res.push_back(root->val);
        preorderTraversal(root->left);
        preorderTraversal(root->right);
        return res;
    }
};

  方法2:迭代

      从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压右孩子再压左孩子

      在这个算法中,输出到最终结果的顺序按照 Top->Bottom 和 Left->Right,符合前序遍历的顺序

///迭代
class Solution{
public:
     vector<int> preorderTraversal(TreeNode* root)
     {
         vector<int>res;
         if(root==NULL) return res;
         stack<TreeNode*>ss;
         ss.push(root);
         while(!ss.empty())
         {
             TreeNode* temp=ss.top();
             ss.pop();
             res.push_back(temp->val);
             if(temp->right)
                ss.push(temp->right);
             if(temp->left)
                ss.push(temp->left);
         }
         return res;
     }
};

(2)二叉树的中序遍历

 方法1:递归 

class Solution {
private:
    vector<int>res;
public:
    vector<int> inorderTraversal(TreeNode* root) {
        if(root==NULL) return res;
        inorderTraversal(root->left);
        res.push_back(root->val);
        inorderTraversal(root->right);
        return res;
    }
};

  方法2:迭代

 

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        if(root==NULL) return res;
        stack<TreeNode*>ss;
        TreeNode* cur=root;
        while(cur!=NULL || !ss.empty())
        {
            while(cur!=NULL)
            {
                ss.push(cur);
                cur=cur->left;
            }
            cur=ss.top();
            ss.pop();
            res.push_back(cur->val);
            cur=cur->right;
        }
        return res; 
    }
};

 

(3)二叉树的后序遍历

 方法1:递归

 

///递归
class Solution {
public:
    vector<int> res;
    vector<int> postorderTraversal(TreeNode* root) {
        if(root==NULL) return res;
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        res.push_back(root->val);
        return res;
    }
};

 

   方法2:迭代

 

LeetCode官方给的一种简直BUG的解法:从根节点开始依次迭代,弹出栈顶元素输出到输出列表中,然后依次压入它的所有孩子节点,按照从上到下、从左至右的顺序依次压入栈中。

因为深度优先搜索后序遍历的顺序是从下到上、从左至右,所以需要将输出列表逆序输出。

///迭代
class Solution{
public:
    vector<int> postorderTraversal(TreeNode* root) 
    {
        stack<TreeNode*>ss;
        vector<int>res;
        if(root==NULL) return res;
        ss.push(root);
        while(!ss.empty())
        {
            TreeNode* temp=ss.top();
            ss.pop();
            res.push_back(temp->val);
            if(temp->left)
                ss.push(temp->left);
            if(temp->right)
                ss.push(temp->right);
        }
         reverse(res.begin(),res.end());
        return res;
    }
};

 另外一种迭代方式

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode *> path;
        unordered_set<TreeNode *> _set; // 记录已经访问的结点

        if (root) path.push(root);

        while (!path.empty()) {
            auto node = path.top();

            bool leftVisited = true, rightVisited = true;

            // 左右结点判断先后顺序不能互换,因为需要先把右结点放进 stack中
            if (node->right && _set.find(node->right) == _set.end()) {
                rightVisited = false;
                path.push(node->right);
            }

            if (node->left && _set.find(node->left) == _set.end()) {
                leftVisited = false;
                path.push(node->left);
            }

            if (leftVisited && rightVisited) { // 左右结点已经访问过了,才可以访问当前结点
                ret.push_back(node->val);
                _set.insert(node);
                path.pop(); // 访问过了,从path中移除
            }
        }

        return ret;
    }
};

 

 (3)二叉树的后序遍历

case1:分层次输出结果

给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

BFS需要借助队列啦
class Solution {
public:
    vector<vector<int>>res;
    queue<TreeNode*>qq;
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL) return res;
        vector<int>vec;
        vec.push_back(root->val);
        res.push_back(vec);
        qq.push(root);
        while(qq.size())
        {
            int cnt=qq.size();
            vector<int>vec;
            for(int i=0;i<cnt;i++)
            {
                TreeNode* cur=qq.front();
                qq.pop();
                if(cur->left)
                {
                    qq.push(cur->left);
                    vec.push_back(cur->left->val);
                }
                if(cur->right)
                {
                    qq.push(cur->right);
                    vec.push_back(cur->right->val);
                }
            }
            if(!vec.empty())//vec不为空数组时才压入res;
                res.push_back(vec);
        }
        return res;
  
    }
};

 



 

 

 

 

 

posted @ 2019-12-03 13:51  任仁人  阅读(364)  评论(0编辑  收藏  举报