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

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

 

前序遍歷的實現:

// 前序遍歷 ----基於遞歸
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);
    }
}
相關文章
相關標籤/搜索