线索二叉树分析与比较

中序线索二叉树

图片名称 图片名称

中序线索二叉树
逻辑结构:
用空分支指向前驱和后继,如何线索化?
一个结点如果有空指针,则左空指针指向其遍历序列前驱,如果有右空指针指向遍历序列后继

typedef struct TBTNode {
    int data;
    int lTag;//0指向左孩子,1指向前驱
    int rTag;//
    TBTNode *lchild;
    TBTNode *rchild;
}TBTNode;

中序线索化代码:

//pre为p的父结点/前驱
void inThread(TBTNode *p,TBTNode *&pre)
{
    if(p != NULL)
    {
        inThread(p->lchild,pre);
        //把p左孩子指向p的前驱
        if(p->lchild == NULL)
        {
            p->lchild = pre;
            p->lTag = 1;
        }
        //把p右孩子指向p的后继
        //我们采用pre指向p来连接(为什么不用p来指向p的后继呢,因为我们没有p的后继这个变量)
        
        if(pre != NULL && pre->rchild == NULL)
        {
            pre->rchild = p;
            pre->rTag = 1;
        }
        //pre与p同步,那么p是如何再领先pre到下一步呢,
        //当递归结束,p回溯,就实现了p走到pre的下一步了
        pre = p;
        inThread(p->rchild,pre);
    }
}

在这里插入图片描述
中序线索二叉树:
开头:最左的左孩子
结尾:最右的右孩子
给一个结点如何找到它遍历的前驱和后继
找前驱:从这个结点左走一步,再一直往右走到底。
比如:A1的前驱,左走一步A2,然后一直右走,是A5
找后继:从这个结点右走一步,再一直往左走。
比如:A1的后继,右走一步A3,再一直左走,是A6

前序线索二叉树

逻辑结构相似,遍历方式不一样。
一个结点如果有空指针,则左空指针指向其遍历序列前驱,如果有右空指针指向遍历序列后继

//pre为p的父结点/前驱
void preThread(TBTNode *p,TBTNode *&pre)
{
    if(p != NULL)
    {
        //把p左孩子指向p的前驱
        if(p->lchild == NULL)
        {
            p->lchild = pre;
            p->lTag = 1;
        }
        //把p右孩子指向p的后继
        //我们采用pre指向p来连接(为什么不用p来指向p的后继呢,因为我们没有p的后继这个变量)
        
        if(pre != NULL && pre->rchild == NULL)
        {
            pre->rchild = p;
            pre->rTag = 1;
        }
        //pre与p同步,那么p是如何再领先pre到下一步呢,
        //当递归结束,p回溯,就实现了p走到pre的下一步了
        pre = p;
        //左指针不是线索,才往左走,避免绕圈陷入死循环
        if(p->lTag == 0)
        	preThread(p->lchild,pre);
        if(p->rTag == 0)
        	preThread(p->rchild,pre);
    }
}
图片名称

如何在前序线索二叉树上执行前序遍历操作?
第一个结点是根结点。找后继结点,如果一个结点的左指针不空,并且左指针不是线索,那么左指针指向其后继(是线索的话就指向其前驱了)。如果一个结点其左指针空,其右指针一定指向指向其后继结点(普通和线索一样)

void preOrder(TBTNode *tbt)
{
	if(tbt != NULL)
	{
		TBTNode *p = tbt;
		while(p!=NULL)
		{
			//把左边找完
			while(p->lTag == 0)
			{
				visit(p);
				p = p->lChild;
			}
			//右指针指向的是后继
			visit(p);
			p = p->lChild;
		}
	}
}

后序线索二叉树

图片名称
void postThread(TBTNode *p,TBTNode *&pre)
{
    if(p != NULL)
    {
        
        postThread(p->lchild,pre);
        postThread(p->rchild,pre);
        if(p->lchild == NULL)
        {
            p->lchild = pre;
            p->lTag = 1;
        }
        if(pre != NULL && pre->rchild == NULL)
        {
            pre->rchild = p;
            pre->rTag = 1;
        }
        pre = p;
    }
}

后序考点:

  • 如果结点是二叉树的根,则其后继为空。
  • 若结点是其双亲的右孩子;或结点是其双亲的左孩子且其双亲没有右子树;则其后继为双亲结点。
  • 若结点是其双亲的左孩子,且其双亲有右子树,则其后继为双亲右子树上按后序遍历列出的第一个结点。(不要多想,要有大局观,它就是想说,从左子树跨到右子树了。)

代码的记法:
1.初始状态
初始:p = A1, pre = NULL

2.两个连接的if语句
if(p->lchild == NULL)
if(pre != NULL && pre->rchild == NULL)
两个if() 放xxxThread()前面叫前序,放中间叫中序,放最后叫后序.

3.只有前序前面需要加if(p->xTag == 0)来判断(避免形成环),中序不需要这个if。

//只有前序线索才需要检测是否有环
if(p->lTag == 0)
     xxThread(p->lchild,pre);
if(p->rTag == 0)
     xxThread(p->rchild,pre);

两个if都放在inThread()前面就是前序线索二叉树的代码,两个if都放在两个inThread ()中间,就是中序线索二叉树的代码。

三种线索二叉树的比较

在这里插入图片描述
前序:找后继结点方便,但不方便找前驱结点

(比如:A2->A1,只知道A2如何找A1

中序:前驱和后继都能很方便的找到。
找前驱:从这个结点左走一步,再一直往右走到底。
找后继:从这个结点右走一步,再一直往左走。
(在前面有)

后序:找前驱和找后序都复杂。(具体过程在前面的总结)

(所有找前驱,考研考的相当少,几乎不考,主要考的是找后继的方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jieshenai

为了遇见更好的文章

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值