线索二叉树---摘录

来源:互联网 发布:李迪华 知乎 编辑:程序博客网 时间:2024/06/05 02:22
1. 线索化和线索化实质
   将二叉树变为线索二叉树的过程称为线索化。
   按某种次序将二叉树线索化的实质是:按该次序遍历二叉树,在遍历过程中用线索取代空指针。


2.二叉树的中序线索化 
(1)分析
  算法与中序遍历算法类似。只需要将遍历算法中访问结点的操作具体化为建立正在访问的结点与其非空中序前趋结点间线索。
  该算法应附设一个指针pre始终指向刚刚访问过的结点(pre的初值应为NULL),而指针p指示当前正在访问的结点。
   结点*pre是结点*p的前趋,而*p是*pre的后继。


(2)将二叉树按中序线索化的算法
 typedef enum { Link,Thread} PointerTag; //枚举值Link和Thread分别为0,1
 typedef struct node{
DataType data;
PointerTag ltag,rtag; //左右标志
Struct node *lchild,*rchild;
 } BinThrNode;\\线索二叉树的结点类型
 
 typedef BinThrNode *BinThrTree;
 BinThrNode *pre=NULL; //全局量


 void lnorderThreading(BinThrTree p)
 { //将二叉树p中序线索化
if(p)
{
//p非空时,当前访问结点是*p
InorderThreading(p->lchild); //左子树线索化
//以下直至右子树线索化之前相当于遍历算法中访问结点的操作
p->ltag = (p->lchild)  Link:Thread; //左指针非空时左标志为Link
//(即0),否则为Thread(即1)
p->rtag = (p->rchild)  Link:Thread;
 
if(pre)
{
//若*p的前趋*pre存在
if(pre->rtag==Thread) //若*p的前趋右标志为线索
 pre->rchild=p; //令*pre的右线索指向中序后继
if(p->ltag==Thread) //*p的左标志为线索
p->lchild=pre; //令*p的左线索指向中序前趋
} // 完成处理*pre的线索
 
pre=p; //令pre是下一访问结点的中序前趋
InorderThreeding(p->rehild); //右子树线索化
}//endif
 } //InorderThreading


(3)算法分析
  和中序遍历算法一样,递归过程中对每结点仅做一次访问。因此对于n个结点的二叉树,算法的时间复杂度亦为O(n)。
 
 4.查找指定节点的后继节点
 BinThrNode *InorderSuccessor(BinThrNode *p)
 {  //在中序线索树中找结点*p的中序后继,设p非空
BinThrNode *q;
if (p->rtag == Thread) //*p的右子树为空
Return p->rchild; //返回右线索所指的中序后继
else
{
q = p->rchild; //从*p的右孩子开始查找
while (q->ltag==Link)
q=q->lchild; //左子树非空时,沿左链往下查找
return q; //当q的左子树为空时,它就是最左下结点
} //end if
 }
 该算法的时间复杂度不超过树的高度h,即O(h)。
 
 5.查找指定节点的前驱结点
 BinThrNode *Inorderpre(BinThrNode *p)
 {  //在中序线索树中找结点*p的中序前趋,设p非空
BinThrNode *q;
if(p->ltag == Thread) //*p的左子树为空
return p->lchild; //返回左线索所指的中序前趋
else
{
q = p->lchild; //从*p的左孩子开始查找
while(q->rtag == Link)
q = q->rchild; //右子树非空时,沿右链往下查找
return q; //当q的右子树为空时,它就是最右下结点
} //end if
 } 
  
由上述讨论可知:对于非线索二叉树,仅从*p出发无法找到其中序前趋(或中序后继),
而必须从根结点开始中序遍历,才能找到*p的中序前趋(或中序后继)。
线索二叉树中的线索使得查找中序前趋和中序后继变得简单有效。




在前序线索二叉树中,找某一点*p的前序后继也很简单,仅从*p出发就可以找到;
但找其前序前趋也必须知道*p的双亲结点。当树中结点未设双亲指针时,
同样要进行从根开始的前序遍历才能找到结点*p的前序前趋。


6. 遍历线索二叉树
  遍历某种次序的线索二叉树,只要从该次序下的开始结点开发,反复找到结点在该次序下的后继,直至终端结点。
  遍历中序线索二叉树算法:
  void TraverseInorderThrTree(BinThrTree p)
  { //遍历中序线索二叉树
   if(p){//树非空
    while(p->ltag==Link)
     p=p->lchild; //从根往下找最左下结点,即中序序列的开始结点
    do{
     printf("%c",p->data); //访问结点
     p=InorderSuccessor(p); //找*p的中序后继
    }while(p)
   }//endif
  }//TraverselnorderThrTree
 分析:
  ① 中序序列的终端结点的右线索为空,所以do语句的终止条件是p==NULL。
  ② 该算法的时间复杂性为O(n)。因为是非递归算法,常数因子上小于递归的遍历算法。因此,若对一棵二叉树要经常遍历,
      或查找结点在指定次序下的前趋和后继,则应采用线索链表作为存储结构为宜。
  ③ 以上介绍的线索二叉树是一种全线索树(即左右线索均要建立)。许多应用中只要建立左右线索中的一种。

  ④ 若在线索链表中增加一个头结点,令头结点的左指针指向根,右指针指向其遍历序列的开始或终端结点会更方便。


摘录自:http://student.zjzk.cn/course_ware/data_structure/web/SHU/shu6.4.1.htm