zoukankan      html  css  js  c++  java
  • 二叉树的前序/中序/后序遍历方法的递归与循环的实现

    对于二叉树的三种遍历方法, 递归方法实现起来简单,明白。但是效率不好,并且不安全,可能会栈溢出。循环的实现,肯定是基于栈的数据结构来实现,要复杂一些。代码如下:

    前序遍历的实现:

    // 前序遍历 ----基于递归
    void PreorderTraversal(BinaryTreeNode* pRoot_)
    {
        // 为空时,直接返回了
        if (!pRoot_)
            return;
    
        std::cout << pRoot_->m_nValue << " ";
        PreorderTraversal(pRoot_->m_pLeft);
        PreorderTraversal(pRoot_->m_pRight);
    }
    
    // 前序遍历 ----基于循环
    void PreorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
    {
        // 为空时,直接返回
        if (!pRoot_)
            return;
    
        // 需要使用到栈数据结构, 先把右子树放到栈中,再把左子树放到栈中
        stack<BinaryTreeNode*> _StackNodes;
        _StackNodes.push(pRoot_);
        while (!_StackNodes.empty())
        {
            BinaryTreeNode* _pCurrentNode = _StackNodes.top();
            _StackNodes.pop();
            std::cout << _pCurrentNode->m_nValue << " ";
    
            // 把非空的左右子节点放到栈中, 注意:要先放右节点,再放左节点
            BinaryTreeNode* _pRight = _pCurrentNode->m_pRight;
            BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft;
            if (_pRight)
                _StackNodes.push(_pRight);
            if (_pLeft)
                _StackNodes.push(_pLeft);
    
        }   
    }

    中序遍历的实现:

    // 中序遍历 ---- 基于递归
    void InorderTraversal(BinaryTreeNode* pRoot_)
    {
        // 为空时,直接返回
        if (!pRoot_)
            return;
    
        InorderTraversal(pRoot_->m_pLeft);
        std::cout << pRoot_->m_nValue << " ";
        InorderTraversal(pRoot_->m_pRight);
    }
    
    // 中序遍历 ---- 基于循环
    void InorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
    {
        // 为空时,直接返回
        if (!pRoot_)
            return;
    
        // 初始化一个栈数据结构
        std::stack<BinaryTreeNode*> _StackNodes;
    
        // 先一股脑地把左子节点放到的栈中, 因为这时栈顶的叶结点就是我们遍历的起点
        BinaryTreeNode* _pCurrentNode = pRoot_;
        while (_pCurrentNode)
        {
            _StackNodes.push(_pCurrentNode);
            _pCurrentNode = _pCurrentNode->m_pLeft;
        }
    
        while (!_StackNodes.empty())
        {
            // 遍历栈顶的节点
            BinaryTreeNode* _pCurrentNode = _StackNodes.top();
            _StackNodes.pop();
            std::cout << _pCurrentNode->m_nValue << " ";
    
            // 即然遍历到了当前的节点,说明了它的左子树已经遍历完了,不需要管了。 我们现在
            // 需要关注的是:当前节点的右子树是否为空了, 如果不为空,则需要去处理一下了。
            _pCurrentNode = _pCurrentNode->m_pRight;
            while (_pCurrentNode)
            {
                _StackNodes.push(_pCurrentNode);
                _pCurrentNode = _pCurrentNode->m_pLeft;
            }
        }
    }

    后序遍历的实现:

    // 后序遍历 ---- 基于递归
    void PostorderTraversal(BinaryTreeNode* pRoot_)
    {
        // 为空时,直接返回
        if (!pRoot_)
            return;
    
        PostorderTraversal(pRoot_->m_pLeft);
        PostorderTraversal(pRoot_->m_pRight);
        std::cout << pRoot_->m_nValue << " ";
    }
    
    // 后序遍历 ---- 基于循环
    void PostorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
    {
     // 为空时,直接返回
        if (!pRoot_)
            return;
    
        // 使用一个栈的数据结构
        std::stack<BinaryTreeNode*> _StackNodes;
    
        // 把我们查找第一个应该遍历的node的路径上经过的所有node按顺序一股脑地压入栈中
        BinaryTreeNode* _pCurrentNode = pRoot_;
        while (_pCurrentNode)
        {
            _StackNodes.push(_pCurrentNode);
            // 优先选择不为空的左节点,如果左节点为空,再考虑右节点(右节点为空也没有关系)
            if (_pCurrentNode->m_pLeft)
                _pCurrentNode = _pCurrentNode->m_pLeft;
            else
                _pCurrentNode = _pCurrentNode->m_pRight;
        }
    
        while (!_StackNodes.empty())
        {
            // 遍历栈顶的节点
            BinaryTreeNode* _pCurrentNode = _StackNodes.top();
            _StackNodes.pop();
            std::cout << _pCurrentNode->m_nValue << " ";
    
            // 既然遍历到了当前节点,说明它的左子树与右子树都遍历完了,不需要管了。我们现在
            // 需要关注的是: 如果当前节点为父节点的左节点,则需要判断父节点的右节点是否为空.
            // 如果不为空,则需要去处理父节点的右节点了。
            //
            // 另外,如果当前节点不右父节点的右节点,也不需要管,因为接下来会去遍历父节点。
            if (!_StackNodes.empty() && _pCurrentNode == _StackNodes.top()->m_pLeft)
            {
                _pCurrentNode = _StackNodes.top()->m_pRight;
                while (_pCurrentNode)
                {
                    _StackNodes.push(_pCurrentNode);
                    // 优先选择左节点,当左节点为空时,再选择右节点(右节点为空,也没事)
                    if (_pCurrentNode->m_pLeft)
                        _pCurrentNode = _pCurrentNode->m_pLeft;
                    else
                        _pCurrentNode = _pCurrentNode->m_pRight;
                }
            }
        }
    }

    最后,补充一个宽度优先遍历的实现,即一层层地遍历:

    分层遍历:

    // 宽度优先遍历,就是一层层地遍历。 这肯定是基于单端队列来实现
    void BreadthFirstTraversal(BinaryTreeNode* pRoot_)
    {
        if (!pRoot_)
            return;
    
        std::queue<BinaryTreeNode*> _QueueNodes;
        _QueueNodes.push(pRoot_);
        while (!_QueueNodes.empty())
        {
            BinaryTreeNode* _pCurrentNode = _QueueNodes.front();
            _QueueNodes.pop();
            std::cout << _pCurrentNode->m_nValue << " ";
    
            // 把当前节点的左右非空子节点放入到队列中
            BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft;
            BinaryTreeNode* _pRight = _pCurrentNode->m_pRight;
            if (_pLeft)
                _QueueNodes.push(_pLeft);
            if (_pRight)
                _QueueNodes.push(_pRight);
        }
    }
  • 相关阅读:
    浅析Go中的MPG模式(一)
    panic: assignment to entry in nil map
    Golang 新手可能会踩的 50 个坑
    小刘的go面试题
    go 单元测试整理
    go test 测试单个文件和测试单个函数
    mac pro锁屏后没有声音了怎么处理
    go json返回时间字符串处理time.Time类型
    php求一个字符串中不重复的最长子串
    业务订单号生成算法,每秒50W左右,不同机器保证不重复,包含日期可读性好
  • 原文地址:https://www.cnblogs.com/yinheyi/p/10668108.html
Copyright © 2011-2022 走看看