線索化二叉樹


                        線索二叉樹

基本概念:

  n個結點的二叉鏈表中共有2n個鏈域,但只有n-1個有用的非空鏈域,其余n+1個是空的,利用這n+1個空鏈域來存放遍歷過程中結點的前驅和后繼;規定:若結點有左子樹,則其LChild指向左孩子,否則LCHild指向前驅;若結點有右子樹,則其RChild域指向右孩子,否則指向后繼。

  Ltag=0,CHild指向左孩子;Ltag=1,CHild指向遍歷的前驅

  Rtag=0,RHild指向左孩子;Rtag=1,RHild指向遍歷的前驅

  指向前驅和后繼的指針稱為線索。以這種結構組成的二叉鏈表作為二叉樹的存儲結構,稱為線索鏈表。對二叉樹以某種次序進行遍歷並且加上線索的過程稱為線索化。線索化的二叉樹稱為線索二叉樹

算法思想:

  1. 中序線索化采用中序遞歸遍歷算法框架
  2. 加線索的操作就是訪問結點的操作
  3. 加線索操作需要利用剛訪問的結點與當前節點的關系,因此設置一個指針pre,始終記錄剛訪問過的結點,操作如下

    a.如果當前遍歷結點root的左子域為空,左子域指向pre;

    b.如果前驅pre的右子域為空,則讓右子域指向當前遍歷結點root;

    c.為下次做准備,訪問當前結點root作為下一個訪問結點的前驅pre

 

廢話不多說了,直接上代碼:

#include <stdio.h>
#include <stdlib.h>

typedef struct Tree
{
    int data,Ltag,Rtag;//數據,左右標志 
    struct Tree *LChild,*RChild;//左右孩子指針域 
}Tree,*Trees;
Trees pre=NULL;

void InitTree(Trees *boot)//初始化二叉樹,只有一個根節點,無左右孩子 
{
    *boot=(Trees)malloc(sizeof(Tree));
    (*boot)->LChild=(*boot)->RChild=NULL;
    (*boot)->Ltag=(*boot)->Rtag=0; 
}

void CreateTree(Trees &boot)//創建二叉樹,具體操作參考上一篇《樹與二叉樹》 
{
    int ch;
    scanf("%d",&ch);
    if(ch==0)
        boot=NULL;
    else
    {
        boot=(Trees)malloc(sizeof(Tree));
        boot->data=ch;
        boot->LChild=boot->RChild=NULL;
        boot->Ltag=boot->Rtag=0;
        CreateTree(boot->LChild);
        CreateTree(boot->RChild);
    }
}
//添加線索 
void InThread(Trees &boot)
{
    if(boot!=NULL)
    {
        InThread(boot->LChild);//線索化左子樹 
        if(boot->LChild==NULL)
        {
            boot->Ltag=1;
            boot->LChild=pre;//置前驅線索 
        }
        if(pre!=NULL&&pre->RChild==NULL)
        {
            pre->RChild=boot;
            pre->Rtag=1;
        }
        pre=boot;//當前訪問節點為下一個訪問節點的前驅 
        InThread(boot->RChild);//線索化右子樹 
    }
} 

Trees InOrderThread(Trees &rt)//建頭結點 
{
    Trees thrt;
    if(!(thrt=(Trees)malloc(sizeof(Tree))))
    {
        printf("頭結點創建失敗.\n");
        exit(1);
    }
    
    thrt->Ltag=0;//等於零指向左孩子  1
    thrt->Rtag=1;//等於一指向遍歷的前驅 2
    thrt->RChild=thrt;//右回指針,指向自己(頭結點) 3
    if(!rt)
        thrt->LChild=thrt;//若二叉樹為空,建立左回指針(也指向頭結點)
    else
    {
        thrt->LChild=rt;//rt==boot,也就是二叉樹的根 
        pre=thrt;//pre指向頭結點 
        InThread(rt);//為二叉樹加線索 
        pre->RChild=thrt;//同上1
        pre->Rtag=1;//同上2
        thrt->RChild=pre;//同上3
    }
    return thrt;
}

//中序找前驅 
void InPre(Trees boot)
{
    Trees q=NULL;
    if(boot->Ltag==1)
        pre=boot->LChild;
    else
    {
        for(q=boot->LChild;q->Rtag==0;q=q->RChild)
            pre=q;    
    }    
    if(pre)
        printf("中序找到的前驅為:%d\n",pre->data);    
    else
        printf("無前驅.\n");
}

//中序找后繼 
void InNext(Trees boot)
{
    Trees q=NULL;
    if(boot->Rtag==1)
        pre=boot->RChild;
    else
    {
        for(q=boot->RChild;q->Ltag==0;q=q->LChild)
            pre=q;
    }
    if(pre)
        printf("中序找到的后繼為:%d\n",pre->data);
    else
        printf("中序遍歷無后繼.\n");
}

//中序遍歷序線索樹上的第一個結點 
Trees InFirst(Trees boot)
{
    Trees p=boot;
    if(!p)
        return NULL;
    while(p->Ltag==0)
        p=p->LChild;
    return p;
}

//中序遍歷線索二叉樹 
void TInOrder(Trees &thrt)
{
    Trees p;
    p=thrt->LChild;
    while(p!=thrt)
    {
        while(p->Ltag==0)
            p=p->LChild;
        printf("%d ",p->data);
        while(p->Rtag==1&&p->RChild!=thrt)
        {
            p=p->RChild;
            printf("%d ",p->data);        
        }
        p=p->RChild;
    }
    printf("\n");
}

int main()
{
    Trees boot=NULL;
    printf("創建二叉樹,輸入零結束:\n");
    CreateTree(boot);
    
    Trees thrt;//頭結點 
    thrt=InOrderThread(boot);
    TInOrder(thrt);//中序遍歷線索二叉樹 
    
    InPre(boot);//中序找前驅 
    
    InNext(boot);//中序找后繼 
    
    Trees bt=InFirst(boot);//中序遍歷序線索樹上的第一個結點
    printf("中序遍歷序線索樹上的第一個結點為:%d\n",bt->data);
    
    return 0;
}

 結果:

  


免責聲明!

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



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