数据结构-线索二叉树

线索二叉树 1.什么是线索二叉树 遍历二叉树是按一定的规则将二叉树中所有结点排列为一个有序序列,这实质上是对一个非线性的数据结构进行线性化的操作。经过遍历的结点序列,除第一个结点和最后一个结点以外,其余每个结点都有且仅有一个直接前驱结点和一个直接后继结点。 当以二叉链表作为存储结构时,只能找到结点的左、右孩子的信息,而不能直接得到结点任意一个序列中的直接前驱结点和直接后继结点是什么,这种信息只有在对二叉树遍历的动态过程中才能得到。若增加前驱指针和后继指针将使存储密度进一步降低。 在用二叉链表存储的二叉树中,单个结点的二叉树有两个空指针域;两个结点的二叉树有三个空指针域。 不难证明:n个结点的二叉树有n+1个空指针域。也就是说,一个具有n个结点的二叉树,若采用二叉链表存储结构,在其总共2n个指针域中只有n-1个指针域是用于存储结点子树的地址,而另外n+1个指针域存放的都是∧(空指针域)。因此,可以充分利用二叉链表存储结构中的那些空指针域,来保存结点在某种遍历序列中的直接前驱结点和直接后继结点的地址信息。 指向直接前驱结点或指向直接后继结点的指针称为线索(thread),带有线索的二叉树称为线索二叉树。对于二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化。 2.线索二叉树的方法 由于二叉树结点的序列可由不同的遍历方法得到,因此,线索二叉树也分为先序线索二叉树、中序线索二叉树和后序线索二叉树三种。在三种线索二叉树中一般以中序线索化用得最多,所以下面以图6-10所示的二叉树为例,说明中序线索二叉树的方法。中序线索二叉树的具体步骤如下。 (1)先写出原二叉树的中序遍历序列:DGBAECHF。 (2)若结点的左子树为空,则此线索指针将指向前一个遍历次序的结点。 (3)若结点的右子树为空,则此线索指针将指向下一个遍历次序的结点。

线索二叉树的结点结构定义如下。 typedef struct threadbinode { datatype data; //二叉链表的结点 bool ltag; //左孩子标志,当ltag为true时,表示左孩子存在(lchild所指为该结点左 孩子);反之,则表示左孩子不存在(lchild所指为该结点直接后继结点) struct threadbinode lchild; //左孩子指针 bool rtag; //其含义与ltag类似 struct threadbinode rchild; //右孩子指针 }ThreadBiNode; //二叉链表结点的类型 二叉树进行中序线索化的递归函数代码如下。 void InThreadBiTree(ThreadBiNode *T, ThreadBiNode *pre,ThreadBiNode * rear) { //pre指向整个二叉树T中序序列的直接前驱节点 //rear指向整个二叉树T中序序列的直接后继节点 if(trueT-> ltag) InThreadBiTree(T-> lchild,pre,T); //左子树的直接前驱结点就是整棵二叉树的直接前驱结点,左子树的直接后继结点就是整棵 二叉树的根结点 else T-> lchild=pre; if(trueT-> rtag) InThreadBiTree(T-> rchild,T,rear); //右子树的直接前驱结点就是整棵二叉树的根结点,右子树的直接后继结点就是整棵二叉树 的直接后继结点 else T-> rchild=rear; } 由于整棵二叉树中序序列的直接前驱结点和直接后继结点均可为空,因此对二叉树T进行中序线索化可采用语句InThreadBiTree(T,NULL,NULL)。 另外,为了便于操作,在存储线索二叉树时需要增设一个结点,其结构与其他线索二叉树的结点结构一样。但是头结点的数据域不存放信息,它的左指针域指向二叉树的根结点,右指针域指向自己。而原二叉树在某种序列遍历下的第一个结点的前驱线索和最后一个结点的后继线索都指向头结点。 3.线索二叉树的优点 (1)利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度比一般二叉树的遍历速度快,并且节约存储空间。 (2)任意一个结点都能直接找到它相应遍历顺序的直接前驱结点和直接后继结点。 4.线索二叉树的缺点 (1)结点的插入和删除较麻烦,并且速度也比较慢。 (2)线索子树不能共用。

经验分享 程序员 微信小程序 职场和发展