线索二叉树
1.简介
线索二叉树主要为了方便确定二叉树某一个元素的直接前驱和直接后继而来的。它在链式二叉树的基础上将结点的空链域加以利用,并用来存放节点的前驱和后继信息。为了区别结点链域是为指向其左(右)孩子还是指向前驱(后继),对原来的链式二叉树的结点结构进行改进:
其中当lchild链域指向左孩子时,lTag= 0;当lchild链域指向其前驱时,lTag= 1。rchild类似。
采用这种储存结构(实际上为二叉链表)的二叉树的即为线索二叉树。将链式二叉树变为线索二叉树的过程就是线索化。也就是将链式二叉树中的结点的空链域修改为指向结点前驱或者后继结点。
如下图所示的二叉树:
当该二叉树采用普通第一种结点结构存储时,它有8个空链域(上图中灰色标记的链域)。一般地,n个节点的二叉树,会有n+1个空链域。当该二叉树采用第二种结点结构存储时,其如下所示:
在线索化时,为了能够仿照线性表的存储结构,为二叉树添加一个头结点。并将该头结点的lchild链域指向该二叉树的根结点,其rchild链域指向遍历时访问的最后一个节点。同时将二叉树遍历时访问的第一个元素的lchild链域和最后一个元素的rchild链域指向该头结点。线索化后,即将该二叉树中的空链域指向其遍历(
各种遍历方式不同,结点的前驱和后继都不相同)时的前驱或者后继,其线索二叉树中的线索如下图所示:
上图即为中序遍历该二叉树时的线索化的结果。将上图按照线索进行拆分即可以得到如下图所示的按照中序遍历得到的二叉树的线索链表。
2.代码
采用中序遍历二叉树时,其线索化代码如下所示:
Status inOrderThreading(binaryThrTree &thrT, binaryThrTree T){ //thrT 为线索化后的头结点,T为待线索化的二叉树 binaryThrTree pre; thrT = new binaryThrNode;//新建头结点 if(!thrT) exit(-1); thrT->lTag = Link; //头结点左链域标识为指针 thrT->rTag = Thread; //头结点右链域标识为线索 thrT->rchild = thrT; //头结点右链域标识为指向中序遍历访问的最后一个结点的线索(先初始化为指向该节点本身) if(!T)thrT->lchild = thrT;//如果二叉树为空,则将头结点左链域指向头结点 else{ thrT->lchild = T; //如果二叉树非空,则将头结点左链域指向二叉树的根 pre = thrT;//记录刚访问过的结点 InThreading(T ,pre);//线索化二叉树 pre->rchild = thrT;//线索化结束后,pre保存了中序遍历之后最后访问的节点,然后让该节点的右链域指向头结点 pre->rTag = Thread;//标识为线索 thrT->rchild = pre;//将头结点的右链域指向中序遍历之后最后一个访问的节点 } return 1; }
void InThreading(binaryThrTree p, binaryThrTree &pre){ if(p){ InThreading(p->lchild, pre);//线索化当前结点的左子树 if(!p->lchild){p->lTag = Thread;p->lchild = pre;}//前驱线索 if(!pre->rchild){pre->rTag = Thread;pre->rchild = p;}//后继线索 pre = p; InThreading(p->rchild, pre);//线索化当前结点的右子树 } }
待二叉树线索化完成后,即可以对其进行遍历:
Status InOrderTraverse_Threads(binaryThrTree thrT){ binaryThrTree p = thrT->lchild;//找到二叉树的根结点 while(p != thrT){//二叉树为空或者遍历完线索化后的二叉树时p指向头结点 while(p->lTag == Link) p = p->lchild; cout<<p->data<<" ";//访问左子树为空的结点 while(p->rTag == Thread && p->rchild!= thrT){//按照线索访问后继结点 p = p->rchild; cout<<p->data<<" "; } p = p->rchild; } return 1; }
完整代码如下:
// binaryThrTree.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <string> #include <iostream> using namespace std; typedef string tElemType; typedef int Status; typedef enum PointerTag{Link, Thread}; typedef struct binaryThrNode{ tElemType data; struct binaryThrNode *lchild, *rchild; PointerTag lTag, rTag; }binaryThrNode, *binaryThrTree; Status createthrTree(binaryThrTree &thrT){ //create a thread binary tree in pre-order. //after this work finished, the attributes lTag and rTag of this thread binary tree is not initialised. string starts; cin>>starts; if(starts == "#") thrT = NULL; else{ thrT = new binaryThrNode; if (!thrT) exit(-1); thrT->data = starts; thrT->lTag = Link; thrT->rTag = Link; createthrTree(thrT->lchild); createthrTree(thrT->rchild); } return 1; } Status inOrderTraverse(binaryThrTree T){ if(T){ inOrderTraverse(T->lchild); cout<<(T->data)<<" "; inOrderTraverse(T->rchild); } return 1; } void InThreading(binaryThrTree p, binaryThrTree &pre){ if(p){ InThreading(p->lchild, pre); if(!p->lchild){p->lTag = Thread;p->lchild = pre;} if(!pre->rchild){pre->rTag = Thread;pre->rchild = p;} pre = p; InThreading(p->rchild, pre); } } Status inOrderThreading(binaryThrTree &thrT, binaryThrTree T){ binaryThrTree pre; thrT = new binaryThrNode; if(!thrT) exit(-1); thrT->lTag = Link; thrT->rTag = Thread; thrT->rchild = thrT; if(!T)thrT->lchild = thrT; else{ thrT->lchild = T; pre = thrT; InThreading(T ,pre); pre->rchild = thrT; pre->rTag = Thread; thrT->rchild = pre; } return 1; } Status InOrderTraverse_Threads(binaryThrTree thrT){ binaryThrTree p = thrT->lchild; while(p != thrT){ while(p->lTag == Link) p = p->lchild; cout<<p->data<<" "; while(p->rTag == Thread && p->rchild!= thrT){ p = p->rchild; cout<<p->data<<" "; } p = p->rchild; } return 1; } int _tmain(int argc, _TCHAR* argv[]) { binaryThrTree T = new binaryThrNode; if(!T) exit(-1); cout<<"Try to create a thread binary tree..."<<endl; createthrTree(T); cout<<"creation is finished!"<<endl; cout<<"Try to traverse it:"<<endl; inOrderTraverse(T); binaryThrTree thrT; cout<<endl<<"Try to thread the binary thread tree..."<<endl; inOrderThreading(thrT, T); cout<<"Try to traverse the binary thread tree with threads:"<<endl; InOrderTraverse_Threads(thrT); delete thrT; delete T; system("pause"); return 0; }
效果如下: