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,就是这样。不要忘记了,线索二叉树有三种结构哦~

posted @ 2021-11-23 23:11  莫恼卿卿  阅读(102)  评论(0)    收藏  举报