中序遍历的线索二叉树

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

/*
 * 这里是不带头结点的线索二叉树,带头结点的以后再写
 * 线索二叉树:
 *      把树型逻辑结构变成线性逻辑结构,可以顺序访问二叉树中的元素,用来加速查找前驱和后继
 *      pay attention to:只是逻辑结构改变了,物理结构不受影响
 * 线索二叉树的基本操作:
 *      1.找线索二叉树的第一个结点
 *      2.找线索二叉树的最后一个结点
 *      3.找线索二叉树中某个结点的前驱结点
 *      4.找线索二叉树中某个结点的后继结点
 *      5.线索二叉树的遍历(中序)  因为线索二叉树逻辑结构是线性的,找到开始结点,然后一直访问右指针即可
 * LNR线索二叉树的创建:是递归的,这里仅仅介绍中序递归遍历创建线索二叉树
 *      分两个部分函数实现:1.中序线索化二叉树算法 2.中序创建线索化二叉树算法
 * LNR线索二叉树的盲点:
 *      注意:必须牢记
 *      1.一个节点的前驱和后继可能都有两种情况,因为后继或前驱可能是孩子结点或没关系的结点
 *      2.因为你把二叉树变成了线性结构,所以才会出现这种情况,正常LNR二叉树后继结点就是右孩子,前驱结点就是左孩子
 */

typedef char ElemType;
//线索二叉树的存储结构
typedef struct node
{
    ElemType data;  //数据域
    struct node *lchild,*rchild;  //左右孩子指针
    int ltag,rtag;   //线索标志位 0指向孩子,1指向前驱或后继
}ThreadNode,*ThreadTree;
// 不带头结点的递归创建线索二叉树
void CreateThreadTree(ThreadTree &tree)
{
    char ch;
    if ((ch=getchar())=='#')
        tree=NULL;
    else
    {
        tree=(ThreadTree)malloc(sizeof(ThreadNode));
        tree->data=ch;
        CreateThreadTree(tree->lchild);
        CreateThreadTree(tree->rchild);
    }
}
/*
 * pre是一个指向刚刚访问过的结点的指针
 * 中序线索化  递归问题,大问题是给所有结点都线索化,小问题有三个左子树先线索化,根节点线索化,右子树线索化
 * 设大问题为:f(tree,pre)
 * 又因为是中序遍历,所以
 * 大问题f(tree,pre)等价于f(b->lchild,pre)+根节点线索化+f(b->rchild,pre)
 * 所以递归模型是:
 *      return NULL;    当tree==NULL时,递归出口
 *      f(b->lchild,pre);根节点线索化+f(b->rchild,pre)   其他情况时
 * 假设,左子树已经线索完了,那么我们只要写线索根节点的代码即可
 *  至此,递归模型建立完成
 *
 *  最后我们发现,这个线索化代码,没有处理pre的有指针,所以,我们要在写一个专门建立线索二叉树的算法(CreateInThread)
 *  并且在线索完了之后,处理pre的有孩子指针和rtag标志位
 */
void InThread(ThreadTree &tree,ThreadTree &pre)
{
    //pre是一个指向刚刚访问过节点的指针
    if (tree!=NULL)
    {
        InThread(tree->lchild,pre);  //线索完左子树
        //处理根节点  有三种情况
        if (tree->lchild==NULL)  //根节点左子树不存在时
        {
            tree->lchild=pre;  //左孩子指针指向前驱结点 pre,其实是指向了空
            tree->ltag=1;
        }
        if (pre!=NULL&&pre->rchild==NULL)
        {
            pre->rchild=tree;
            pre->rtag=1;
        }
        pre=tree;
        InThread(tree->rchild,pre);
    }
}
//不带头结点的建立中序线索二叉树算法
void CreateInThread(ThreadTree &tree)
{
    ThreadTree pre=NULL;
    if (tree!=NULL)
    {
        InThread(tree,pre);
        pre->rchild=NULL;
        pre->rtag=1;
    }
}
//不带头结点的求中序线索二叉树的第一个结点
ThreadTree FirstNode(ThreadTree tree)
{
    while (tree->ltag==0)  //返回最左下结点
        tree=tree->lchild;
    return tree;   //左子树为空,返回根节点
}
//不带头结点的中序线索二叉树的最后一个节点
ThreadTree LastNode(ThreadTree tree)
{
    while (tree->rtag==0)   //找到第一个最右下角结点
    {
        tree=tree->rchild;
    }
    return tree;   //返回最后一个的结点指针
}
//求不带头结点的中序线索二叉树中某个节点的后继结点
ThreadTree NextNode(ThreadTree p)
{
    /*思路:因为是LNR访问方式,所以结点p的后继有两种情况
     *  1.当p的右子树存在时,p的后继结点是p的右子树上的第一个结点(p的右子树上的最左下结点)  p的子孙
     *  2.当p的右子树不存在时,p的后继结点是p的后继  p的后继
     */
    if (p->rtag==0)  //p的后继是p的子孙结点
        return FirstNode(p->rchild);
    else
        return p->rchild;  //否则返回p的后继结点
}
//求不带头结点的中序线索二叉树中某个节点的的前驱结点
ThreadTree PriorNode(ThreadTree p)
{
    /*
     * 思路:p的前驱有两种情况  LNR时
     *  1.当p的左子树存在时,p的前驱是左子树上的最后一个结点  p的前驱是p的子孙 ltag=0情况
     *  2.当p的左子树不存在时,p的前驱是p的前驱  即ltag=1情况
     */
    if (p->ltag==0)
        return LastNode(p->lchild);
    else
        return p->lchild;  //直接返回前驱结点
}
//遍历线索二叉树的代码(中序LNR)  一直访问右指针即可
void InOrderThread(ThreadTree &tree)
{
    tree=FirstNode(tree);
    while (tree)   //当tree存在时,一直沿着右指针遍历到最后一个结点
    {
        printf("%c",tree->data);
        tree=NextNode(tree);
    }
}
//销毁线索二叉树
void DestoryTree(ThreadTree tree)
{
    if (tree)
    {
        DestoryTree(tree->lchild);
        DestoryTree(tree->rchild);
        free(tree);
    }
}
int main()
{
    ThreadTree tree;
    CreateThreadTree(tree);
    CreateInThread(tree);
    printf("中序遍历线索二叉树为:");
    InOrderThread(tree);
    DestoryTree(tree);
    return 0;
}

 

原文地址:https://www.cnblogs.com/nanfengnan/p/14590578.html