C线索化儿叉树(前序/中序/后序)

【1】个人想法:前后看了2~3周吧感觉真难。不参考别人的代码,要自己想出来难度很大。但也可以试着想一想

代码是用C写的。


【2】重点知识:

(1)二叉树并不难理解

(2)n个节点的二叉树,有空域n+1个。证明:n个节点有域2n个;那个树形图里面,一条线代表占用了一个域,只有根上面没线,所以共占用n-1个域。那剩下的域就是n+1个了。

(3)给二叉树加上线索后,感觉就像是个循环链表一样的。但并不是,具体像什么并不能直观地想象出来,或许不需要


【3】关于代码:代码里面比较有意思的函数是:

create_tree(二叉树初始化。一开始觉得这个函数挺简单,后来觉得有点意思);

thrTree_mid_inner(中序线索化。它把前驱,后继分在2个循环里面赋值,这个想法很重要);

last_ergodic(后序线索化二叉树遍历。我想了一阵后序到底该怎么遍历,看到可以反过来遍历才觉得醍醐灌顶)


【4】代码

#include <stdio.h>
#include <malloc.h>
 
typedef char ElemType;
typedef enum {
    OK=1,
    ERROR=0
}Status;
typedef enum {Link=0,Thread=1}clue;
typedef struct Tnode{
    ElemType data;
    struct Tnode *lchild,*rchild;
    clue ltag,rtag;
}TNode,*thrBitTree;
thrBitTree pre;
 
void create_tree(thrBitTree *T,char **arr){
    char c;
    sscanf(*arr,"%c",&c);
    (*arr)++;
     
    if(c=='.'){
        *T=NULL;
    }else{
        *T=(thrBitTree)malloc(sizeof(TNode));
        (*T)->data=c;
        (*T)->ltag=(*T)->rtag=Link;
        create_tree(&(*T)->lchild,arr);
        create_tree(&(*T)->rchild,arr);
    }
}
 
void visit(TNode* T){
    if(T){
        printf("%c ",T->data);
    }
}
void visit_d(TNode* T){
    if(T){
        printf("%d|%c|%d\n",T->ltag,T->data,T->rtag);
    }
}
 
//递归前序遍历
void pre_ergodic_r(thrBitTree T){
    if(T){
        visit(T);
        pre_ergodic_r(T->lchild);
        pre_ergodic_r(T->rchild);
    }
}
//递归中序遍历
void mid_ergodic_r(thrBitTree T){
    if(T){
        mid_ergodic_r(T->lchild);
        visit(T);
        mid_ergodic_r(T->rchild);
    }
}
//递归后序遍历
void last_ergodic_r(thrBitTree T){
    if(T){
        last_ergodic_r(T->lchild);
        last_ergodic_r(T->rchild);
        visit(T);
    }
}
 
//-----------------------------前序线索化----
void pre_ergodic(thrBitTree P){
    thrBitTree T=(thrBitTree)malloc(sizeof(TNode));
    T=P->lchild;
    while(T!=P){
        visit(T);
        if(T->ltag==Link){
            T=T->lchild;
        }
        else{
            T=T->rchild;
        }
    }
}
 
void thrTree_pre_inner(thrBitTree T){
    if(T){
        if(T->lchild==NULL){
            T->lchild=pre;
            T->ltag=Thread;
        }
        if(pre->rchild==NULL){
            pre->rchild=T;
            pre->rtag=Thread;
        }
        pre=T;
        if(T->ltag==Link)
            thrTree_pre_inner(T->lchild);
        if(T->rtag==Link)
            thrTree_pre_inner(T->rchild);
    }
}//-----------------------------endl----
 
//-----------------------------中序线索化----
void mid_ergodic(thrBitTree P){
    thrBitTree T=(thrBitTree)malloc(sizeof(TNode));
    T=P->lchild;
    while(T!=P){
        while(T->ltag==Link){
            T=T->lchild;
        }
        visit(T);
        while(T->rtag==Thread && T->rchild!=P){
            T=T->rchild;
            visit(T);
        }
        T=T->rchild;
    }
}
 
void thrTree_mid_inner(thrBitTree T){
    if(T){
        thrTree_mid_inner(T->lchild);
        if(T->lchild==NULL){
            T->lchild=pre;
            T->ltag=Thread;
        }
        if(pre->rchild==NULL){
            pre->rchild=T;
            pre->rtag=Thread;
        }
        pre=T;
        thrTree_mid_inner(T->rchild);
    }
}//-----------------------------endl----
 
//-----------------------------后序线索化----
typedef struct SNode{
    ElemType data;
    struct SNode* next;
}SNode,*StackList;


//带头节点的栈初始化
void initStack(StackList *S){
    *S=(StackList)malloc(sizeof(SNode));
    (*S)->next=NULL;
}


void Push(StackList S,ElemType e){
    if(S==NULL) return;


    SNode* newNode=(SNode*)malloc(sizeof(SNode));
    newNode->data=e;
    newNode->next=S->next;
    S->next=newNode;
}


void printStack(StackList S){
    if(S==NULL) return;
    SNode* p=S->next;
    while(p){
        printf("%c ", p->data);
        p=p->next;
    }
    printf("\n");
}


//可以按 根-右-左 再倒过来
//倒过来这个,用栈实现吧
void last_ergodic(thrBitTree P){
    thrBitTree T=P->rchild;
    StackList S=NULL;
    initStack(&S);
    while(T!=P){
        //visit(T);
        Push(S,T->data);
        if(T->rtag==Link){
            T=T->rchild;
        }
        else{
            T=T->lchild;
        }
    }
    printStack(S);
}
 
void thrTree_last_inner(thrBitTree T){
    if(T){
        if(T->ltag==Link)
            thrTree_last_inner(T->lchild);
        if(T->rtag==Link)
            thrTree_last_inner(T->rchild);
        if(T->lchild==NULL){
            T->lchild=pre;
            T->ltag=Thread;
        }
        if(pre->rchild==NULL){
            pre->rchild=T;
            pre->rtag=Thread;
        }
        pre=T;
    }
}
//-----------------------------endl----
 
//给树加头节点
void thrTree(thrBitTree *P,thrBitTree T,void (*thrTree_inner)()){
    *P=(thrBitTree)malloc(sizeof(TNode));
    (*P)->rchild=*P;
    (*P)->rtag=Thread;
    (*P)->ltag=Thread;
    if(T==NULL){
        (*P)->lchild=*P;
    }
    else{
        (*P)->lchild=T;
        pre=*P;
        thrTree_inner(T);
         
        //防止后续线索化中根节点的右孩子被污染
        if(pre!=(*P)->lchild){
            pre->rtag=Thread;
            pre->rchild=*P;
        }
        (*P)->rchild=pre;
    }
}
 
void main(){
    thrBitTree P,T;
 
    //char *arr="ab.c..de...";
    char *arr="HDA..C.B..GF.E....";
    create_tree(&T,&arr);
     
    //递归 遍历
    printf("recrution:\n");
 
    printf("pre_r:");
    pre_ergodic_r(T);
    printf("\n");
    printf("mid_r:");
    mid_ergodic_r(T);
    printf("\n");
    printf("last_r:");
    last_ergodic_r(T);
    printf("\n\n");
 
    //无递归 遍历
    printf("no-recrution:\n");
 
    thrTree(&P,T,thrTree_pre_inner);
    printf("pre:");
    pre_ergodic(P);
    printf("\n");
 
    free(P);free(T);
    arr="HDA..C.B..GF.E....";
    create_tree(&T,&arr);
    thrTree(&P,T,thrTree_mid_inner);
    printf("mid:");
    mid_ergodic(P);
    printf("\n");
 
    free(P);free(T);
    arr="HDA..C.B..GF.E....";
    create_tree(&T,&arr);
    thrTree(&P,T,thrTree_last_inner);
    printf("last_reverse:");
    last_ergodic(P);
 
    printf("\n");
}


【5】结果

C:\Users\xxx>gcc D:/testP/cc.c -o D:/testP/cc.o


C:\Users\xxx>D:/testP/cc.o
recrution:
pre_r:H D A C B G F E
mid_r:A D C B H F E G
last_r:A B C D E F G H


no-recrution:
pre:H D A C B G F E
mid:A D C B H F E G
last_reverse:A B C D E F G H

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值