二叉树的非递归遍历

先序遍历

先序遍历可以简单的理解为:

首先访问根节点,如果根节点的左子树存在,那么递归的对根节点的左子树进行先序遍历,如果根节点的右子树存在,那么递归的对根节点的右子树进行先序遍历。访问顺序为父-左-右。

    3         例如给定左边的二叉树,那么它的先序遍历为:3,9,20,15,7
   / \
  9  20
    /  \
   15   7 

可以利用一个辅助栈完成非递归的先序遍历,我们先将根节点压入栈中,在栈非空的时候弹出辅助栈的栈顶节点,在弹出时对这个节点进行访问。既然访问的顺序为父-左-右,我们可以先将当前节点的右儿子压入栈中,再将当前节点的左儿子压入栈中,重复上述过程,直到所有节点被访问完。

vector<int> preorderTraversal(TreeNode* root) 
{
    stack<TreeNode*> tmp;
    vector<int> res;
    if(root != NULL)
        tmp.push(root);
    else
        return res;
    while(!tmp.empty())
    {
        root = tmp.top();
        res.push_back(root->val);
        tmp.pop();
        if(root->right != NULL)
            tmp.push(root->right);
        if(root->left != NULL)
            tmp.push(root->left);       
    }
    return res; 
}

中序遍历

中序遍历可以简单的理解为:

首先,如果根节点的左子树存在,那么递归的对根节点的左子树进行先序遍历,再访问根节点,如果根节点的右子树存在,那么递归的对根节点的右子树进行先序遍历。访问顺序为左-父-右。

    3     它的中序遍历为:9,3,15,20,7
   / \
  9  20
    /  \
   15   7 

首先将二叉树的最左节点依次压入栈中,在栈非空的时候弹出栈顶并访问,如果这个节点的右子树存在,那么对右子树也进行上述的操作,直到遍历完所有节点。

vector<int> inorderTraversal(TreeNode* root) 
{
    stack<TreeNode*> tmp;
    vector<int> res;
    while(root != NULL || !tmp.empty())
    {
        if(root != NULL) //将最左节点压入
        {
            tmp.push(root);
            root = root->left;
        }
        else
        {
            TreeNode* cur = tmp.top(); //访问栈顶
            tmp.pop();
            res.push_back(cur->val);
            root = cur -> right;
        }    
    }
    return res;          
}

后序遍历

后序遍历可以简单的理解为:

首先,如果根节点的左子树存在,那么递归的对根节点的左子树进行先序遍历,如果根节点的右子树存在,那么递归的对根节点的右子树进行先序遍历,再访问根节点。访问顺序为左-右-父。

   3        它的后序遍历为:9,15,7,20,3
  / \
 9  20
   /  \
  15   7 

后序遍历可以通过简单的修改先序遍历得到,先序遍历中改变左右儿子的压栈顺序可以将访问顺序变为父-右-左,再将其逆序便可以得到后序遍历的顺序左-右-父。

vector<int> postorderTraversal(TreeNode* root) 
{
    stack<TreeNode*> tmp;
    stack<int> res1;
    vector<int> res;
    if(root != NULL)
        tmp.push(root);
    else
        return res;
    while(!tmp.empty())
    {
        root = tmp.top();
        res1.push_back(root->val);
        tmp.pop();
        if(root->left != NULL)
            tmp.push(root->left); 
        if(root->right != NULL)
            tmp.push(root->right);          
    }
    while(!res1.empty())
    {
        res.push_back(res1.top());
        res1.pop();
    }
    return res; 
}

层次遍历

层次遍历顾名思义就是按层遍历,逐层的从左到右访问所有节点。

    3      它的层次遍历为:3,9,20,15,7;为了更清楚地分层,可以将其表示为[[3],[9,20],[15,7]];
   / \
  9  20
    /  \
   15   7

可以利用辅助队列完成层次遍历,首先根节点入队列,在队列非空时,队首出队列并访问,如果有左儿子,那么左二子入队列,如果有右儿子,那么右儿子入队列。当队列为空时,说明已经访问了所有的节点。

vector<vector<int>> levelOrder(TreeNode* root) 
{
    vector<vector<int>> res;
    queue<TreeNode*> q1,q2,q;
    vector<int> tmp;
    if(root == NULL)
        return res;
    q1.push(root);
    while(!q1.empty())
    {
        TreeNode* cur = q1.front();
        q1.pop();
        if(cur->left != NULL)
            q2.push(cur->left);
        if(cur->right != NULL)
            q2.push(cur->right);
        tmp.push_back(cur->val);
        if(q1.empty())
        {
            res.push_back(tmp);
            tmp.clear();
            q = q2;
            q2 = q1;
            q1 = q;
        }       
    }
    return res;   
}
posted @ 2019-06-25 14:31  番茄起司汤  阅读(156)  评论(0编辑  收藏  举报