线索二叉树前序中序后序遍历

完全抄袭的大佬的链接 :
https://blog.csdn.net/weixin_39956356/article/details/80142461

(先序,中序)线索化及遍历
由于篇幅的原因,这里仅仅展示(先序,中序)线索化及遍历,主要原因这两个有很高的相识度,思想几乎一样。仅仅是访问顺序不同!!!
接下来都是按先序操作实现功能(整体流程),中序操作实现功能(整体流程),后序操作实现功能(整体流程)。即一个一个讲完整在进行下一个。
后序线索化及遍历(我的下篇文章):

首先,不管在哪种线索化,都需要一个pre指针指向上次访问的结点,因为我们的目的是找到前驱和后继,那么就肯定需要两个指针(一前一后)。

一:先序线索化及遍历
递归与先序访问顺序

在这里插入图片描述
对应代码

//先序线索化
void PreThreading(BiThrTree p)
{
    if (p)
    {
        if (!p->lchild)                                     //前驱线索
        {
            p->lchild = pre;
            p->LTag = Thread;
        }
        if (pre != NULL && !pre->rchild)                    //后继线索
        {
            pre->rchild = p;
            pre->RTag = Thread;
        }
        pre = p;
        if(p->LTag == Link)
            PreThreading(p->lchild);                        //左子树线索化
        if (p->RTag == Link)
            PreThreading(p->rchild);                        //右子树线索化
    }
}

2:先序线索化添加虚设头结点(建立双向循环链表)
作用:规范,方便,忠实数据结构书上的的做法(转一圈就结束),如果你觉得麻烦,不加也可以,但必须了解其遍历的前因后果,以便知道遍历结束的循环出口。
在这里插入图片描述

//先序线索化二叉树(添加头结点)建立双向循环链表
Status PreOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
    if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
        return OVERFLOW;
    Thrt->LTag = Link;  Thrt->RTag = Thread;                //左指针指向头结点
    Thrt->rchild = Thrt;                                    //右指针回指   
    if (!T)
        Thrt->lchild = Thrt;                                //二叉树为空,左指针回指
    else
    {
        Thrt->lchild = T;   pre = Thrt;                     //虚设头节点指向头节点
        PreThreading(T);
        pre->rchild = Thrt;  pre->RTag = Thread;            //处理最后一个节点指向虚设头结点
        Thrt->rchild = pre;
    }
    return OK;
}

3:先序线索化遍历
先序线索化遍历前驱与后继图

在这里插入图片描述
核心思想:递归与访问顺序
1:如果你不添加虚设的头结点,也可以利用先序线索化的唯一NULL(G->rchild)作为循环出口
2:这里需要注意如果使用先序线索化就要用先序线索化遍历

在这里插入图片描述

//先序遍历--必须要先序线索化
Status PreOrderTraverse(BiThrTree HeadNode, Status(*visit)(TElemType e))
{
    BiThrTree p = HeadNode->lchild;                                 //虚设头结点指向根节点
    while (p != HeadNode)                                           //转一圈回来结束
    {
        while (p->lchild != NULL && p->LTag == Link)                //先序一直向左走
        {
            visit(p->data);                                         //1:访问根节点
            p = p->lchild;                                          //向左走
        }
        visit(p->data);                                             //2:访问最左边节点
        if(p->LTag == Thread)                                       //3:遍历右子树(如果有子树,则返回215行,往左走)
            p = p->rchild;                              
    }
    return OK;
}

二:中序线索化及遍历
1:中序线索化
递归与先序访问顺序
在这里插入图片描述
在这里插入图片描述

//先序线索化
void PreThreading(BiThrTree p)
{
    if (p)
    {
        if (!p->lchild)                                     //前驱线索
        {
            p->lchild = pre;
            p->LTag = Thread;
        }
        if (pre != NULL && !pre->rchild)                    //后继线索
        {
            pre->rchild = p;
            pre->RTag = Thread;
        }
        pre = p;
        if(p->LTag == Link)
            PreThreading(p->lchild);                        //左子树线索化
        if (p->RTag == Link)
            PreThreading(p->rchild);                        //右子树线索化
    }
}

2:先序线索化添加虚设头结点(建立双向循环链表)
作用:规范,方便,忠实数据结构书上的的做法(转一圈就结束),如果你觉得麻烦,不加也可以,但必须了解其遍历的前因后果,以便知道遍历结束的循环出口。

在这里插入图片描述

//先序线索化二叉树(添加头结点)建立双向循环链表
Status PreOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
    if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
        return OVERFLOW;
    Thrt->LTag = Link;  Thrt->RTag = Thread;                //左指针指向头结点
    Thrt->rchild = Thrt;                                    //右指针回指   
    if (!T)
        Thrt->lchild = Thrt;                                //二叉树为空,左指针回指
    else
    {
        Thrt->lchild = T;   pre = Thrt;                     //虚设头节点指向头节点
        PreThreading(T);
        pre->rchild = Thrt;  pre->RTag = Thread;            //处理最后一个节点指向虚设头结点
        Thrt->rchild = pre;
    }
    return OK;
}

3:先序线索化遍历
先序线索化遍历前驱与后继图
在这里插入图片描述
核心思想:递归与访问顺序
1:如果你不添加虚设的头结点,也可以利用先序线索化的唯一NULL(G->rchild)作为循环出口
2:这里需要注意如果使用先序线索化就要用先序线索化遍历

在这里插入图片描述

//先序遍历--必须要先序线索化
Status PreOrderTraverse(BiThrTree HeadNode, Status(*visit)(TElemType e))
{
    BiThrTree p = HeadNode->lchild;                                 //虚设头结点指向根节点
    while (p != HeadNode)                                           //转一圈回来结束
    {
        while (p->lchild != NULL && p->LTag == Link)                //先序一直向左走
        {
            visit(p->data);                                         //1:访问根节点
            p = p->lchild;                                          //向左走
        }
        visit(p->data);                                             //2:访问最左边节点
        if(p->LTag == Thread)                                       //3:遍历右子树(如果有子树,则返回215行,往左走)
            p = p->rchild;                              
    }
    return OK;
}

二:中序线索化及遍历
1:中序线索化
递归与先序访问顺序
在这里插入图片描述
在这里插入图片描述

//中序线索化
void InThreading(BiThrTree p)
{
    if (p)
    {
        InThreading(p->lchild);             //左子树线索化
        if (!p->lchild)                     //前驱线索
        {
            p->LTag = Thread;
            p->lchild = pre;
        }
        if (!pre->rchild)                   //后继线索
        {
            pre->RTag = Thread;
            pre->rchild = p;
        }
        pre = p;
        InThreading(p->rchild);             //右子树线索化
    }
}

2:先序线索化添加虚设头结点(建立双向循环链表)
作用:规范,方便,忠实数据结构书上的的做法(转一圈就结束),如果你觉得麻烦,不加也可以,但必须了解其遍历的前因后果,以便知道遍历结束的循环出口。
在这里插入图片描述

//中序线索化二叉树(添加头结点)--双向链表
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
    if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))      //虚设根节点
        return OVERFLOW;
    Thrt->LTag = Link;  Thrt->RTag = Thread;                //左指针指向头结点
    Thrt->rchild = Thrt;                                    //右指针回指   
    if(!T)
        Thrt->lchild = Thrt;                                //二叉树为空,左指针回指
    else
    {
        Thrt->lchild = T;   pre = Thrt;                     //虚设根节点指向头节点
        InThreading(T);
        pre->rchild = Thrt;  pre->RTag = Thread;            //处理最后一个节点指向虚设头结点
        Thrt->rchild = pre;
    }
    return OK;
}

3:中序线索化遍历
中序线索化遍历前驱与后继图

在这里插入图片描述

核心思想:递归与访问顺序
1:如果你不添加虚设的头结点,也可以利用先序线索化的NULL(G->rchild)作为循环出口
2:这里需要注意如果使用中序线索化就要用中序线索化遍历

在这里插入图片描述

//中序遍历--必须要中序线索化
Status InOrderTraverse(BiThrTree HeadNode, Status(*visit)(TElemType e))
{
    BiThrTree p = HeadNode->lchild;                                 // 虚设头结点指向根节点
    while (p != HeadNode) {                                         //转一圈回来结束
        while (p->LTag == Link) {                                   //一直往左走
            p = p->lchild;
        }
        visit(p->data);                                             //1:访问最左边节点
        while (p->RTag == Thread && p->rchild != HeadNode) {        //右子树为线索,且不为头结点
            p = p->rchild;                                          //2:访问分支节点
            visit(p->data);                                         
        }
        p = p->rchild;                                              //回到分支节点,又开始232行,一个新子树
    }
    return OK;
}

后序线索化及遍历:
https://blog.csdn.net/weixin_39956356/article/details/80144113

二叉树的(先,中,后)序的建树
https://blog.csdn.net/weixin_39956356/article/details/80141837

线索二叉树的基本知识:
https://blog.csdn.net/weixin_39956356/article/details/80141980

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值