二叉树的遍历

一共四种遍历方法:先序遍历、中序遍历、后序遍历、层次遍历。代码的实现方式有两种:递归、迭代。

一、先序遍历

先序遍历就是首先访问根节点,然后访问左节点,最后访问右节点。

1.递归

递归的代码很简单,在递归函数中优先访问根节点然后访问左孩子,最后访问右孩子。

    void _PreOrder(PNode& pRoot)
    {
        if (pRoot)
        {
            cout << pRoot->_data << " "; //优先输出根节点
            _PreOrder(pRoot->_LChild);
            _PreOrder(pRoot->_RChild);
        }
    }
    void PreOrder()
    {
        _PreOrder(_pRoot);
        cout << endl;
    }

2.迭代

用迭代法对二叉树进行先序遍历需要借助栈;将暂不访问的右孩子压到堆栈中,直到每棵子树的左孩子全部访问完。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> res;
        while(root)
        {
            res.push_back(root->val); //先把根节点访问了
            if(root->right)          //如果此节点有有孩子,就压栈,以供后续对又孩子进行访问
                st.push(root);
            root = root->left;      //向左子树深入
            if(!root&&!st.empty())  //如果左子树都访问完了,并且堆栈中还存在拥有右孩子的节点
            {
                root = st.top()->right; //根节点更新为其右孩子,并重复判断,进行访问和压栈操作
                st.pop();
            }
        }
        return res;
    }
};

二、中序遍历

中序遍历就是先访问左孩子,然后访问右孩子,最后访问根节点。

1.递归

递归的代码比较类似。

    void _InOrder(PNode& pRoot)
    {
        if (pRoot)
        {
            _InOrder(pRoot->_LChild); //优先对左孩子递归
            cout << pRoot->_data << " "; 
            _InOrder(pRoot->_RChild);
        }
    }
    void InOrder()
    {
        _InOrder(_pRoot);
        cout << endl;
    }

2.迭代

先将根节点和所有的右孩子全部压栈,然后出栈,首先访问左孩子,然后访问右子树,再讲右子树所有左孩子压栈。。。重复。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> res;
        while(root)
        {
            st.push(root);		//对于非空节点无条件压栈
            root = root->left;  //向左子树深入
            if(!root && !st.empty()) //所有左孩子全部进栈
            {
                root = st.top();    //取出栈顶将要访问的孩子
                st.pop();
                while(!root->right && !st.empty())
                {
                    res.push_back(root->val); //如果刚才取出的孩子没有右孩子,则只对其进行访问
                    root = st.top();          //直到找到有右孩子的节点   
                    st.pop();
                }
                res.push_back(root->val); //对于有右孩子的节点,进行访问
                root = root->right;		 //将其右子树根节点作为根节点进行后面的迭代
            }
        }
        return res;
    }
};

三、后序遍历

后序遍历先访问左孩子,然后访问右孩子,最后访问根节点。

1.递归

    void _PostOrder(PNode& pRoot)
    {
        if (pRoot)
        {
            _PostOrder(pRoot->_LChild); //优先对子节点递归
            _PostOrder(pRoot->_RChild);
            cout << pRoot->_data << " ";
        }
    }
    void PostOrder()
    {
        _PostOrder(_pRoot);
        cout << endl;
    }

2.迭代

迭代后序遍历比较复杂。在遍历完左子树时还不能访问根节点,需要再遍历右子树。待右子树遍历完后才访问根节点。所以在辅助栈工作记录中必须注明节点是在左子树还是在右子树。

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

四、层序遍历

程序遍历就是按照从上到下,从左到右的顺序进行遍历。

1.队列实现

void FloorPrint_QUEUE(pTreeNode &Tree) //层序遍历_队列实现
{
    queue < pTreeNode> q;
    if (Tree != NULL)
    {
        q.push(Tree);   //根节点进队列
    }

    while (q.empty() == false)  //队列不为空判断
    {
        cout << q.front()->data << " → "; 

        if (q.front()->leftPtr != NULL)   //如果有左孩子,leftChild入队列
        {
            q.push(q.front()->leftPtr);   
        }

        if (q.front()->rightPtr != NULL)   //如果有右孩子,rightChild入队列
        {
            q.push(q.front()->rightPtr);
        }
        q.pop();  //已经遍历过的节点出队列
    }
}

2.数组实现

void FloorPrint(pTreeNode Tree)  //层序遍历
{
    pTreeNode temp[100];   //创建pTreeNode指针类型的指针数组
    int in = 0;
    int out = 0;

    temp[in++] = Tree;  //先保存二叉树根节点 

    while (in > out)
    {
        if (temp[out])
        {
            cout << temp[out]->data << " → ";
            temp[in++] = temp[out]->leftPtr;
            temp[in++] = temp[out]->rightPtr;
        }
        out++;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值