C语言:二叉树的线索化过程与遍历

二叉树的理解

线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继信息只有在遍历该二叉树时才能得到,所以,线索化的过程就是在遍历的过程中修改空指针的过程。
二叉树的作用:将二叉树线索化后,减少空指针数量,赋予二叉树新的意义。如:在中序线索化后,可以用以近队列存储的方式访问二叉树,加快访问速度和查找效率。
线索化过程
线索化过程于中序递归遍历没太大区别,先递归调用左子树,递归后执行线索操作,再递归调用右子树。

线索操作
在这里插入图片描述

二叉树的存储结构

结构特点:相较于普通二叉树增加左右标记位,ltag、rtag。
标记位l®tag为0,代表l®child指向当前结点的左(右)孩子;
标记位l®tag为1,代表l®child指向当前结点的前(后)继;

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

typedef struct LNode{
    int data;
    struct LNode *leftchild;
    struct LNode *rightchild;
    int ltag,rtag;
}LNode;

使用排序二叉树方式建立二叉树

void InitThreadTree(LNode **root, int Elem){          
    *root = (LNode *)malloc(sizeof(LNode));
    if( !(*root) ){
        printf("Memory allocation for root failed.\n"); return;
    }
    (*root)->data = Elem;
    (*root)->leftchild = NULL;
    (*root)->rightchild = NULL;
    (*root)->ltag = 0;
    (*root)->rtag = 0;
}

void InsertNode(LNode *root,int elem){
    LNode *newnode = NULL;
    LNode *p = root,   *last_p = NULL;
    newnode = (LNode*)malloc(sizeof(LNode));
    if(!newnode){
        printf("Memory allocation for newnode failed.\n");
        return;
    }
    newnode->data = elem;
    newnode->leftchild = NULL;
    newnode->rightchild = NULL;
    newnode->ltag = 0;
    newnode->rtag = 0;
    while(NULL != p){       //循环让头指针指向它要插入结点的位置
        last_p = p;
        if(newnode->data < p->data){
            p=p->leftchild;
        }
        else if(newnode->data > p->data){
            p=p->rightchild;
        }
        else{
            printf("Node to be inserted has existed.\n");
            free(newnode);
        return;
        }
    }
    p=last_p;
    if(newnode->data < p->data){
        p->leftchild=newnode;
    }
    else{
        p->rightchild=newnode;
    }
}

线索化过程

在这里插入图片描述

void InThreadProcess( LNode *P, LNode **Pre ){   //中序线索化
    if(P != NULL){
        InThreadProcess(P->leftchild, Pre);
        if(P->leftchild == NULL){       //左子树为空,找其前驱结点
            P->leftchild = (*Pre);
            P->ltag = 1;
        }
        if((*Pre) != NULL && (*Pre)->rightchild == NULL){  
        //(*Pre)!=NULL 含义是当前结点P不是第一个结点,第一个结点没有后驱结点
        //Pre的右子树为空,为右子树添加后继结点,后继结点为右子树的最左结点
            (*Pre)->rightchild = P;
            (*Pre)->rtag = 1;
        }
        (*Pre) = P;    //注意理解Pre位置,只有此处修改Pre的值
        InThreadProcess(P->rightchild, Pre);
    }
}

void InThread( LNode *T ){     //线索化的主函数
    LNode *Pre = NULL;
    if( T != NULL ){
        InThreadProcess(T, &Pre);
        Pre->rightchild = NULL;
        Pre->rtag = 1;
    }
}

树的前序递归遍历

void visit(LNode *p){
    printf("%d,",p->data);
}

void PreTreverse(LNode *root){
    if(root != NULL){
        visit(root);
        PreTreverse(root->leftchild);
        PreTreverse(root->rightchild);
    }
}

树的线索化遍历

LNode *FirstNode(LNode *p){
    while(p->ltag == 0){
        p = p->leftchild;
    }
    return p;
}

LNode *NextNode(LNode *p){
    if(p->rtag == 0)
        return FirstNode(p->rightchild);
    else
        return p->rightchild;
}

void Inorder(LNode *T){
    LNode *p;
    for(p=FirstNode(T);   p!=NULL;   p=NextNode(p)){
        visit(p);
    }
}

运行主函数

int main(){
    LNode *head=NULL;
    InitThreadTree(&head, 4);
    InsertNode(head, 2);
    InsertNode(head, 1);
    InsertNode(head, 3);
    InsertNode(head, 6);
    InsertNode(head, 5);
    InsertNode(head, 7);           //先序遍历序列为1234567
    //PreTreverse(head);
    InThread(head);
    Inorder(head);
    printf("Hello world!\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值