线索二叉树

线索二叉树是为了便于访问一个结点的前驱和后继的信息。它在每个结点上新增了两个标志位,用来判断当前结点到底有没有左子树/右子树,如果没有,就把其利用起来存前驱/后继的信息。同时它也新增了一个头节点用来将整个二叉树联系起来。具体实现如下,有大量注释便于理解。

#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
#include <malloc.h>
#include <stdlib.h>
typedef struct node
{
    struct node *lchild;
    struct node *rchild;
    int lcFlag, rcFlag;   //用来标记左子树和右子树是不是空的 
    char data;
}Node, *BinTree;
BinTree pre = NULL; 
void Create(BinTree &root)  //创建二叉树(本来指针是不用使用"&"引用符的,但是当指针为NULL时,函数传进来的也是指针的一个拷贝,而不是地址,具体解释看我之前的博客C语言指针传参问题) 
{
    char ch;
    scanf("%c", &ch);
    getchar();
    if(ch == ' ')
        root = NULL;
    else
    {
        if(!(root = (BinTree)malloc(sizeof(Node))))
            exit(0);
        else
        {
            root->data = ch;
            root->lcFlag = 0;
            root->rcFlag = 0;
            Create(root->lchild);
            Create(root->rchild);
        }
    }
}
void InThreading(BinTree p)  //构造中序线索二叉树 
{
    if(p)
    {
        InThreading(p->lchild);  //递归找到最左边的结点 
        if(!p->lchild)          //如果左子树为空,那就将这个空链域用来存前驱 
        {
            p->lcFlag = 1;      //标志位设为1,证明这是存的前驱地址而不是左子树 
            p->lchild = pre;    //本来该存左子树的位置指向前驱节点 
        }
        if(!pre->rchild)        //如果前一个访问的结点的右子树为空,那用来存后继 
        { 
            pre->rcFlag = 1;    //标志位设为1,存放后继地址 
            pre->rchild = p;    //指向后继结点 
        }
        pre = p;                //更新上一个访问的结点 
        InThreading(p->rchild); //线索化右子树 
    }
}
int InOrderThreading(BinTree &head, BinTree root)
{
    if(!(head = (BinTree)malloc(sizeof(Node))))
        exit(0);
    head->lcFlag = 0;      //将头节点的左标志位设为0,把根结点设成它的左子树 
    head->rcFlag = 1;      //右标志位拿来存中序遍历最后一个结点的地址,作为头节点的后继 
    head->rchild = head;   //起初头节点的右结点自己指向自己 
    if(!root)               //根结点为空时,指向自己 
        head->lchild = head;
    else
    {
        head->lchild = root;  //将根结点设为头节点的左子树 
        pre = head;         //更新上一个访问的结点 
        InThreading(root);  //二叉树线索化 
        pre->rchild = head;  //把最后一个结点的右子树的后继存成头节点(形成了一个循环) 
        pre->rcFlag = 1;     
        head->rchild = pre; //头节点的后继设置成最后一个结点 
    }   
    return 1;
}
int InOrder(BinTree head)  //中序遍历线索二叉树 
{ 
    BinTree p = head->lchild;   //将p指向根结点 
    while(p != head)  //由于线索化的时候把最后一个结点的后继设成了根结点,所以只要p!=head,就证明还没遍历完 
    {
        while(p->lcFlag == 0) p = p->lchild;  //中序遍历的特点,来到最左端 
        cout<<p->data<<" ";  //输出对应的值 
        while(p->rcFlag == 1 && p->rchild != head)  //如果右子树是个线索并且还有结点未访问 
        {
            p = p->rchild;      //直接来到后继并输出 
            cout<<p->data<<" ";
        }
        p = p->rchild;  //来到p的右子树,继续以上过程 
    }
    return 1;
}
int main()
{
    BinTree head = NULL, root = NULL;
    Create(root);
    InOrderThreading(head, root);
    InOrder(head);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值