二叉樹的前序/中序/后序遍歷方法的遞歸與循環的實現


對於二叉樹的三種遍歷方法, 遞歸方法實現起來簡單,明白。但是效率不好,並且不安全,可能會棧溢出。循環的實現,肯定是基於棧的數據結構來實現,要復雜一些。代碼如下:

 

前序遍歷的實現:

// 前序遍歷 ----基於遞歸
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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM