线索二叉树

二叉树在连接存储表示中,空链的数目是大于非空链的数目,即在2n个空链中,有n+1个是空链,如果利用这些空链来指向二叉树其他结点的指针,这结点称为线索,具体建立线索树过程:

  • 如果结点的左儿子ptr->left_child为空,则在中序遍历中,用指向在ptr之前访问的结点的指针代替ptr->left_child,即用指向ptr的中序遍历的前驱结点的指针代替空链。
  • 如果结点的右儿子ptr->right_child为空,则在中序遍历中,用指向在ptr之后访问的结点的指针代替ptr->right_child,即用指向ptr的中序遍历的后驱结点的指针代替空链。
    现在有一颗二叉树,其结构如图:
    这里写图片描述
    如果中序遍历这颗二叉树,访问结点的顺序是H,D,I,B,E,A,F,C,G,这里以结点E为例,来说明线索建立的过程吧:
    由于结点E的左儿子是一个空链,所以,用指向在结点之前访问的结点(即B结点)的指针代替这个空链,类似地,由于结点E的右儿子也为空,所以,用在中序遍历中指向E后面结点(即结点A)的指针代替这个空链。
    该二叉树转换为线索二叉树后,该结构如图:
    这里写图片描述
    为了能在内存表示线索二叉树,我们需要增加两个附加域:left_thread和right_thread来区分指针是线索指针还是正常指针,假设ptr是任意一个结点,如果ptr->left_thread=TRUE,那么ptr->left_child是一个线索,否则它就是指向其左儿子的正常指针,right_threadl也类似。构造线索树还加一个额外的头结点,其头结点结构为:
    这里写图片描述
    现在假设已经构建好了上面的中序线索二叉树,那么我们就可以使用该线索二叉树实现中序遍历,其思路:
    对每一个结点ptr来说,如果ptr->right_thread=TRUE,那么根据线索定义,结点ptr的中序后继结点,是ptr->right_child,否则,结点ptr的中序后继结点是从其右儿子开始,沿着左儿子链到达left->thread=TRUE的结点。整个算法时间 复杂度还是O(n)。
    代码实现:
typedef struct thread_tree *thread_pointer;
//线索二叉树结构体
struct thread_tree
{
   short left_thread,right_thread;
   int data;
   thread_pointer left_child,right_child;
};
//寻找该结点的后驱结点
thread_pointer insucc(thread_pointer tree)
{
   thread_pointer temp=tree->right_child;
   if(!tree->right_thread)// 若果不是线索,则沿左儿子查找
      while(!temp->left_thread)
         temp=temp->left_child;
   return temp;
}
//中序线索树遍历输出
void tinorder(thread_pointer tree)
{
   for(;;)
   {
      thread_pointer temp=insucc(tree);
      if(temp==tree) break;
      printf("%d",temp->data);
   }
}

向上面线索二叉树中插入结点,假设我们只考虑插入一个新结点作为结点parent的右儿子情况,那么我们就有以下两种情况要考虑:
若parent的右儿子为空,则插入新结点后,线索二叉树变化如下图:
这里写图片描述
若parent的右儿子存在右子树,则插入新结点后,线索二叉树变化如下图:
这里写图片描述
代码实现:

//在线索二叉树中,向父结点插入新的右儿子
void insert_right(thread_pointer parent,thread_pointer child)
{
   thread_pointer temp;
   child->right_child=parent->right_child;
   child->right_thread=parent->right_thread;
   child->left_child=parent;
   child->left_thread=TRUE;
   parent->right_child=child;
   parent->right_thread=child->right_thread;
   //当时第二种情况时,需查找新插入的结点的后驱结点,
   //并改变其前驱结点为该新的儿子结点
   if(!child->right_thread)
   {
      temp=insucc(child);
      temp->left_child=child;
   }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值