圖解中序遍歷線索化二叉樹,中序線索二叉樹遍歷,C\C++描述


對於一個有n個結點的二叉鏈表,每個結點有指向左右孩子的兩個指針域,所以一共是2n個指針域,而n個結點的二叉樹一共有n-1條分支線路,也就是說,存在2n-(n-1)= n+1個空指針域。
  中序遍歷:HDIBJEFCG,通過遍歷可以知道,結點I的前驅是D,后繼是B
考慮利用那些空地址,存放指向結點在某種遍歷次序下的前驅和后繼結點的地址。  我們把這種指向前驅和后繼的指針稱為線索,加上線索的二叉鏈表稱為線索鏈表,相應的二叉樹就稱為線索二叉樹(Threaded Binary Tree)

對二叉樹進行中序遍歷后,將所有空指針域中的rchild改為指向它們的后繼結點。
  ① H的后繼是D
   ...
  ⑥ G的后繼是NULL,中序遍歷最后一個節點
此時共有6個空指針域被利用
將所有空指針域中的lchild改為指向當前節點的前驅。
  ① H的前驅是NULL,中序遍歷的第一個結點
   ...
  ⑥ G的前驅是C
此時共有5個空指針被利用

最終,空心箭頭實線為前驅,虛線黑箭頭為后繼。線索二叉樹,等於是把一棵二叉樹變成了一個雙向鏈表,這樣插入一個結點、查找一個結點都很方便。對二叉樹以某種次序遍歷使其變為線索二叉樹的過程稱為是線索化
  
為了區分lchild是指向左孩子還是前驅,rchild是指向右孩子還是后繼,需要用一個標志位來區分
■ ltag為0時指向該結點的左孩子,為1時指向該結點的前驅
■ rtag為0時指向該結點的右孩子,為1時指向該結點的后繼
         



    //紅色部分表示前驅和后繼   
二叉樹輸入過程:ABDH##I##EJ###CF##G## 中序遍歷:HDIBJEAFCG
    輸入過程就是 ab##c##
中序遍歷: bac
    輸入過程就是 ABC###DE##F##
中序遍歷:CBAEDF
#include<iostream>
using namespace std;
enum TBT{child=0,thread};  //線索二叉樹結點的指針是指向孩子還是前驅后繼
typedef struct tbt
{
        struct tbt* lchild;
        enum TBT ltag;
        char data;
        enum TBT rtag;
        struct tbt* rchild;
}TBTreeNode,*pTBTree;

int createThreadedBinaryTree(pTBTree& root);

void inorderThreadingBinaryTree(const pTBTree& root);  //中序線索化二叉樹
//在中序遍歷的同時就線索化二叉樹

void inorderThreadedBinaryTreeTraversal(pTBTree root); //中序線索化二叉樹遍歷

int main()
{
        TBTreeNode* root = nullptr;
        int ret = createThreadedBinaryTree(root);
        {
                if(0==ret)
                {
                        inorderThreadingBinaryTree(root);
                        cout<<endl;
                        inorderThreadingBinaryTreeTraversal(root);
                        cout<<endl;
                }
        }
        system("pause");
}





int createThreadedBinaryTree(pTBTree& root)
{
        char data;
        if(cin>>data)
        {
                if('#'==data)
                {
                        root = nullptr;
                        return -1;
                }
                else
                { //用data數據來初始化root結點,然后遞歸建立左子樹和右子樹
                        root = new TBTreeNode();  //創建結點的時候就把結點全部賦值為空
                        root->data = data;
                        createThreadedBinaryTree(root->lchild);
                        createThreadedBinaryTree(root->rchild);
                }
        }
        return 0;
}

static TBTreeNode* pre = nullptr;  //定義一個指針指向中序遍歷當前訪問結點的前一個訪問結點
//線索化結點的后繼要用到,因為中序遍歷順序:左子樹,根結點,右子樹
//前驅可以用剛剛訪問過的結點直接賦值,后繼還沒有訪問,這時候當前結點就是上一個訪問結點pre的后繼
//當然,前提條件是pre的右子樹為空
//pre初始值為nullptr,因為從根結點開始訪問,前一個訪問結點就只能是空了
void inorderThreadingBinaryTree(const pTBTree& root)
{
        if(nullptr==root)
                return ;
        /*  參考中序遍歷
        inorderTraversal(root->lchild);
        cout<<root->data<<" ";
        inorderTraversal(root->rchild);
        */
        inorderThreadingBinaryTree(root->lchild);  //中序遍歷左子樹
        //判斷結點指針域可不可以線索化
        if(nullptr==root->lchild)  //如果左子樹為空,就可以把指針域拿來線索化,指向前驅
        {
                root->lchild = pre;
                root->ltag = thread;
        }
        if(nullptr!=pre&&nullptr==pre->rchild)  //如果當前訪問的根結點不為空,並且前面訪問的結點pre右子樹為空,線索化前一個結點的后繼
        {
                pre->rchild = root;
                pre->rtag = thread;
        }
        //訪問根結點就變成修改前一個訪問結點指針pre
        pre = root;  //之后要訪問右子樹,當前結點自然就是pre
        inorderThreadingBinaryTree(root->rchild);  //中序遍歷右子樹
}

void inorderThreadedBinaryTreeTraversal(pTBTree root)
{
        if(nullptr==root)
                return;
        while(nullptr!=root)
        {
                while(nullptr!=root->lchild&&child==root->ltag)  //兩個條件,區別中序遍歷第一個結點的前驅是nullptr
                {//搜尋從根結點開始的左子樹的最后一個節點
                        root = root->lchild;
                }
                cout<<root->data<<" ";  //輸出根結點
                while(thread==root->rtag)  //該結點有后繼,意味着沒有右子樹
                {
                        cout<<root->rchild->data<<" ";  //直接輸出后繼,也就是中序遍歷當前結點下一個要訪問的結點的值
                        root = root->rchild;  //根結點回溯到后繼
                }
                //該結點有右子樹,root->rtag==child,左子樹已經遍歷完了,這里進入右子樹
                root = root->rchild;  //重復上面的操作
        }
}


免責聲明!

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



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