線索化二叉樹的創建及遍歷

#include<stdio.h>
#include<iostream>
using namespace std;

enum thread
{
    LINK,
    THREAD,
};
template<class T>
struct BinaryTreeThdNode
{
    BinaryTreeThdNode()
        :_pLeft(NULL)
        ,_pRight(NULL)
        ,_pParent(NULL)
        ,_leftThread(LINK)
        ,_rightThread(LINK)
    {}

    T _data;
    BinaryTreeThdNode* _pLeft;//左孩子
    BinaryTreeThdNode* _pRight;//右孩子
    BinaryTreeThdNode* _pParent;//雙親節點
    enum thread _leftThread;//左索引
    enum thread _rightThread;//右索引
};

template<class T>
class BinaryTreeThd
{
public:
    typedef BinaryTreeThdNode<T> Node;

    BinaryTreeThd()//線索二叉樹的構造
        :_pRoot(NULL)
    {}
    BinaryTreeThd(const T array[],size_t size,T invalid)//線索二叉樹的構造
    {
        size_t index=0;
        _pRoot = _CreateTree(_pRoot,array,size,index,invalid);//二叉樹的創建
    }

    void PreThreading()//前序線索化
    {
        Node* prev = NULL;
        _PreThreading(_pRoot,prev);
    }

    void InThreading()//中序線索化
    {
        Node* prev = NULL;
        _InThreading(_pRoot,prev);
    }

    void PostThreading()//後序線索化
    {
        Node* prev = NULL;
        _PostThreading(_pRoot,prev);
    }

    void PreOrder()
    {
        // 找最左邊的節點並訪問路徑上的節點---訪問該最左節點---判斷右子樹是否爲NULL,若爲NULL,訪問連續後繼節點
        //若不爲NULL,則pCur=pCur->_pRight將右子樹重新作爲一棵樹進行訪問
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        while(pCur)
        {
            while(pCur->_leftThread == LINK)
            {
                cout<<pCur->_data<<" ";
                pCur = pCur->_pLeft;
            }
            cout<<pCur->_data<<" ";
            //while(pCur->_rightThread == THREAD)// 判斷該節點的右子樹不存在,訪問後繼節點
            //{
            //  pCur = pCur->_pRight;
            //  cout<<pCur->_data<<" ";
            //}
            //if(pCur->_leftThread == LINK)//再訪問完後繼結點後,可能有兩種情況,存在左子樹,則先訪問左子樹,當作新樹來處理
            //{
            //  pCur = pCur->_pLeft;
            //}
            //if(pCur->_rightThread == LINK)//再訪問完後繼節點,可能沒有左子樹,只有右子樹,或則最左節點右子樹存在,則當作新樹處理
            //{
            //  pCur = pCur->_pRight;
            //}

            //代碼優化---將上面註釋起來的代碼用下面一句代碼替換
            pCur = pCur->_pRight;//全部當作新的樹來處理
        }
    }

    void InOrder()//中序線索化二叉樹的中序遍歷
    {
        // 找到最左端的節點,不訪問路徑,找到之後訪問最左端的節點---再判斷其有無右子樹,若有,作爲新樹去處理,若沒有,連續訪問其後繼節點
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        while(pCur)
        {
            while(pCur->_leftThread == LINK)
            {
                pCur = pCur->_pLeft;
            }
            cout<<pCur->_data<<" ";
            while(pCur->_rightThread == THREAD)
            {
                pCur = pCur->_pRight;
                cout<<pCur->_data<<" ";
            }
            pCur = pCur->_pRight;
        }
    }

    void PostOrder()//後序線索化二叉樹的後序遍歷
    {
        //找到最左節點,不訪問,首先判斷該節點的右子樹是否存在,若不存在,訪問該節點併到其後繼節點,若存在,則訪問右子樹
        //單純的這樣寫,會導致死循環問題,在3的地方,原因是6已經訪問過了,但pCur=pCur->_pRight還是指向6,接着訪問6和3,死循環---解決辦法prev標記訪問過的
        //僅僅是標記過了還是有問題,1沒有辦法訪問到---解決辦法,設立雙親節點
        //特殊的索引樹--左單枝問題,根節點沒有訪問(最後一個節點的右索引是LINK)---解決辦法,if判斷
        //左單支問題
        if(_pRoot==NULL)
            return;
        Node* pCur = _pRoot;
        Node* prev = NULL;//標記訪問過的節點

        while(pCur)
        {
            while(pCur->_leftThread == LINK && pCur->_pRight != prev)
                pCur = pCur->_pLeft;
            while(pCur->_rightThread == THREAD)
            {
                cout<<pCur->_data<<" ";
                prev = pCur;
                pCur = pCur->_pRight;
            }
            if(pCur==_pRoot && pCur->_pRight==NULL)
            {
                cout<<pCur->_data<<" ";
                return ;
            }
            while(pCur && pCur->_pRight==prev)
            {
                cout<<pCur->_data<<" ";
                prev = pCur;
                pCur = pCur->_pParent;
            }
            if(pCur && pCur->_pRight != prev)
            pCur = pCur->_pRight;
        }
    }
private:

    //底層實現

    Node* _CreateTree(Node* pRoot,const T array[],size_t size,size_t& index,T& invalid)//二叉樹的創建
    {
        if(index<size && array[index]!=invalid)
        {
            pRoot = new Node;
            pRoot->_data = array[index];
            pRoot->_pLeft = _CreateTree(pRoot->_pLeft,array,size,++index,invalid);
            if(pRoot->_pLeft)
                pRoot->_pLeft->_pParent = pRoot;
            pRoot->_pRight = _CreateTree(pRoot->_pRight,array,size,++index,invalid);
            if(pRoot->_pRight)
                pRoot->_pRight->_pParent = pRoot;
        }
        return pRoot;
    }
    void _PreThreading(Node* pRoot,Node*& prev)//前序線索化---採用先線索化根節點,判斷根節點左右子樹是否存在,再利用遞歸線索化左子樹和右子樹的的節點
    {
        if(pRoot)
        {
            if(pRoot->_pLeft == NULL)// 線索化當前指針的左指針域
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }

            if(prev!=NULL && prev->_pRight==NULL)//線索化前一個節點的右指針域
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }

            prev=pRoot;
            if(pRoot->_leftThread != THREAD)//防止索引後陷入死循環
            _PreThreading(pRoot->_pLeft,prev);
            if(pRoot->_rightThread != THREAD)
            _PreThreading(pRoot->_pRight,prev);
        }
    }

    void _InThreading(Node* pRoot,Node*& prev)//中序線索化
    {
        if(pRoot)
        {
            _InThreading(pRoot->_pLeft,prev);//找到最左邊的節點

            if(pRoot->_pLeft==NULL)//線索化該節點的左指針域
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }
            if(prev && prev->_pRight==NULL)//線索化前一個節點的右指針域
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }
            prev = pRoot;//該節點的左指針域線索完畢,標記該節點,
            if(pRoot->_rightThread != THREAD)
                _InThreading(pRoot->_pRight,prev);//線索化右子樹的節點
        }
    }

    void _PostThreading(Node* pRoot,Node*& prev)//測試二叉樹的後續索引
    {
        if(pRoot)
        {
            _PostThreading(pRoot->_pLeft,prev);
            _PostThreading(pRoot->_pRight,prev);

            if(pRoot->_pLeft == NULL)
            {
                pRoot->_pLeft = prev;
                pRoot->_leftThread = THREAD;
            }
            if(prev && prev->_pRight==NULL)
            {
                prev->_pRight = pRoot;
                prev->_rightThread = THREAD;
            }
            prev = pRoot;
        }
    }
private:
    Node* _pRoot;
};

測試代碼

void funtest()
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//測試線索二叉樹的創建
    //t1.PreThreading();//測試線索二叉樹的先序索引
    //t1.InThreading();//測試線索二叉樹的中序索引
    //t1.PostThreading();//測試線索二叉樹的後序線索
}

void funtest1()//測試前序索引二叉樹的前序遍歷
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);
    t1.PreThreading();
    t1.PreOrder();
}

void funtest2()//測試中序索引二叉樹的中序遍歷
{
    char str[] = {"124###35##6"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//測試線索二叉樹的創建
    t1.InThreading();
    t1.InOrder();
}

void funtest3()//測試後序索引二叉樹的後序遍歷
{
    //char str[] = {"124###35##6"};
    char str[] = {"12#3##45#6#7##8"};
    char invalid = '#';
    BinaryTreeThd<char> t;
    BinaryTreeThd<char> t1(str,strlen(str),invalid);//測試線索二叉樹的創建
    t1.PostThreading();
    t1.PostOrder();
}

int main()
{
    //funtest();
    //funtest1();
    //funtest2();
    funtest3();
    getchar();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章