• 中序遍历的线索二叉树


    #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;
    }
    

     

  • 相关阅读:
    链接的热键属性accesskey
    链接目标属性
    HTML添加多媒体或音乐
    HTML中的图像
    DreamweaverCS6
    HTML其他基本格式说明
    HTML页面主体常用设置
    网页设计与开发的过程
    文字排版
    选择器
  • 原文地址:https://www.cnblogs.com/nanfengnan/p/14590578.html
Copyright © 2020-2023  润新知