【數據結構】二叉樹(前、中、後)序遍歷的遞歸與非遞歸算法

對於二叉樹,有前序、中序以及後序三種遍歷方法。由於樹的定義自己就是遞歸定義,所以採用遞歸的方法去實現樹的三種遍歷不只容易理解並且代碼很簡潔。而對 於樹的遍歷若採用非遞歸的方法,就要採用棧去模擬實現。在三種遍歷中,前序和中序遍歷的非遞歸算法都很容易實現,非遞歸後序遍歷實現起來相對來講要難一 點。算法


二叉樹前序:訪問根節點->左子樹->右子樹ide

(1)遞歸寫法:spa

依次訪問根節點、左子樹、右子樹,注意遞歸出口的結束。
指針

void _PrevOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        cout << root->_data << "  ";
        _PrevOrder(root->_left);
        _PrevOrder(root->_right);
    }

(2)非遞歸寫法:遞歸

用棧模擬前序遍歷,棧是先進後出的特色,則將無條件地入棧根節點,在彈出根節點以前依次將根節點的右孩子節點和左孩子節點入棧……get

void _PrevOrder(Node* root)
    {
        stack<Node*> s;
        if (root == NULL)
        {
            return;
        }

        s.push(root);
        while (!s.empty())
        {
            root = s.top();
            cout << root->_data << "  ";
            s.pop();
            if (root->_right)
            {
                s.push(root->_right);
            }
            if (root->_left)
            {
                s.push(root->_left);
            }
        }
    }



二叉樹中序:訪問左子樹->根節點->右子樹it

(1)遞歸寫法:io

依次訪問左子樹、根節點、右子樹,注意遞歸出口的結束。class

void _InOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        _InOrder(root->_left);
        cout << root->_data << "  ";
        _InOrder(root->_right);
    }

(2)非遞歸寫法:二叉樹

wKiom1cZpWPDyNITAAAYiZTqWxI956.png

一、藉助棧實現,先順着二叉樹找到最左邊且最下邊的節點3(一邊找一邊入棧),此時入棧序列爲1,2,3。

二、此時按照中序遍歷知道要彈出棧頂元素3,則彈出棧頂元素3。

三、下面該右子樹了,那咱們就要判斷它的右子樹是否爲空,

      若爲空,往回返,該打印2了,那就彈出棧頂元素2。

      若不爲空,該右子樹,指針指向右子樹節點,再重複以前的步驟1,2,3……

void _InOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        stack<Node*> s;
        Node* cur = root;
      
        while (cur || !s.empty())
        {
            while (cur)
            {            
                s.push(cur);                
                cur = cur->_left;
            }

            cur = s.top();    //將棧頂元素保存,以便於後面判斷它是否有右孩子
            cout << s.top()->_data << "  ";        
            s.pop();

            if (cur->_right == NULL)
            {
                cur = NULL;
            }
            else
            {
                cur = cur->_right;
            }
        }
    }


二叉樹後序:訪問左子樹->右子樹->根節點

(1)遞歸寫法:

依次訪問左子樹、右子樹、根節點,注意遞歸出口的結束。

void _PostOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        _PostOrder(root->_left);
        _PostOrder(root->_right);
        cout << root->_data << "  ";
    }

(2)非遞歸寫法:

一、後序遍歷一樣藉助棧實現,先找到最左邊且爲最下面的節點3(一邊入棧一邊找)。

二、節點3若沒有右孩子,那此時就打印節點3了,以後就彈出棧頂節點3

三、節點3如有右孩子,則要去繼續遍歷它的右子樹,等遍歷結束纔可打印3.遍歷重複步驟1,2,3……

void _PostOrderNon_R(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        Node* cur = root;
        Node* prev = NULL;
        stack<Node*> s;
        
        while (cur || !s.empty())
        {
            while (cur)
            {
                s.push(cur);                
                cur = cur->_left;                
            }
            
            cur = s.top();
            if (cur->_right == NULL ||cur->_right==prev )
            {
                cout << cur->_data << "  ";
                s.pop();
                prev = cur;
                cur = NULL;
            }
            else
            {
                cur = cur->_right;
            }
        }                
    }
相關文章
相關標籤/搜索