1. 程式人生 > 其它 >A與B的對話之線索二叉樹

A與B的對話之線索二叉樹

A:什麼是線索二叉樹?

B:先彆著急,你知道二叉樹的定義的儲存結構是什麼嗎?

A:當然知道,就是包含一個值域和兩個指標域的結構體,下圖所示

typedef struct node
{
    char data;
    struct node *left,*right;
}Tree

B:是的,是這樣的,我們可以從程式碼中看出,我們可以通過left和right指標來找到一個結點的左右孩子,對嗎?那如果我們想要找到一個結點的前驅和後繼該怎麼辦呢?

A:很容易找到左右孩子,嗯?前序和後繼?這個是什麼意思?

B:我們知道一個樹有三種遍歷,前後中,比如一個樹的前序遍歷是ABC,我們很容易看出B的前驅結點時A,B的後繼結點是C,當我們遍歷整個二叉樹時,很容易找出某個結點的前驅和後繼,那麼如果我需要直接讓你用程式碼找出一個結點的前驅和後繼,你該怎麼辦呢?

A:新增新的指標嗎?

B:不用不用,你想想我們建立一棵有n個結點的樹時,建立了多少指標?

A:一個結點兩個指標,當然是2n個指標

B:我們一共用了多少個指標呢?

A:n個結點的二叉樹的一共有n-1條分支,那麼我們就用了n-1個指標,還有2n-(n-1)個指標沒有使用

B:對了,我們就可以利用著n+1個指標來指向一個結點的前驅和後繼,而且還利用了空間

A:我有點糊塗了,那應該怎麼做呢?

B:因為我們的結點本生就具有兩個指標,我們如何知道它的左右孩子是指向前驅還是後繼呢?我們在原有的基礎上,加上ltga和rtag來判斷左右指標的指向

ltag==0時代表該結點的left指標指向的是左孩子

ltag==1時代表該結點的left指標指向的是前驅結點

同理可知rtag

A:我明白了!那我們該如何實現呢

B:我們在遍歷二叉樹的時候就會知道結點的前驅,那時候我們就可以給ltag和rtag進行賦值

A:我通過中序遍歷來給ltag和rtag賦值

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

typedef struct node
{
    char data;
    struct node *left,*right;
    int ltag,rlag;
}ThreadTree;//線索二叉樹

ThreadTree *create()//遞迴建立二叉樹
{
    ThreadTree *t=(ThreadTree *)malloc(sizeof(ThreadTree));
    char a;
    cin>>a;
    if(a=='#')
        t=NULL;
    else{
        t->data=a;
        t->left=t->right=NULL;
        t->left=create();
        t->right=create();
    }
    return t;
}

void Zhongxu(ThreadTree *t)//中序線索二叉樹
{
    ThreadTree *pre;//代表後繼
    if(t)
    {
        Zhongxu(t->left);
        if(t->left==NULL)//左是前驅
        {
            t->ltag=1;
            t->left=pre;
        }
        if(pre->right==NULL)//右是後繼
        {
            pre->rlag=1;
            pre->right=t;
        }
        pre=t;
        cout<<t->data;
        Zhongxu(t->right);
    }
}
int main()
{
    ThreadTree *t;
    t=create();//建立二叉樹
    Zhongxu(t);//中序遍歷二叉樹
}

A:這就是線索二叉樹的過程,現在你明白什麼是線索二叉樹了嘛

B:明白了!線索二叉樹就是利用二叉樹空閒的指標,將它指向結點的前驅後者後繼,這樣就很快可以找到一個結點的前驅和後繼

A:Yes,就是這樣。不要忘記了,線索二叉樹有三種結構哦~