我们知道,对称线索二叉树的意义在于,中序遍历这种二叉树时不需要栈结构,也不需要递归实现,而且可以确定某结点在中序序列中的前驱和后继结点。那么现在,如在利用对称序线索二叉树,找到某结点在先根序列中的后继结点呢?
要找到先根序列中的后继结点,可以先直接先根周游已经构造好的对称序二叉树,得到这颗二叉树的先根序列,再搜索后继结点即可。那么,如何先根周游对称序二叉树?
不妨以下面一颗对称序二叉树为例,
除了头结点外,根据对称序线索二叉树的特点,可以把二叉树的各个结点分为三类,左子树不是线索的、左子树是线索而右子树不是线索的、左右子树都是线索的(结点是线索说明该结点不存储信息)。因此,我们可以依照这三种类别对二叉树进行先根遍历:
从二叉树的根结点开始,
1)当左子树不是线索时,顺着左子树一直向下,同时访问遍历到的结点
2)当左子树是线索而右子树不是线索时,访问右子树结点
3)当左、右子树都是线索时,借用线索,跨越父节点,直接访问父节点的右子树,直到右子树为空,先根遍历结束
算法实现如下,
void ThreadPreOrder(pThrTree t) //按先序遍历周游中序线索二叉树
{
pThrTree p =t;
if(t == NULL) return;
else cout<<p->info; //先访问线索二叉树根结点
while(p != NULL){
if(p->llink != NULL && p->ltag == 0){ //左子树不是线索时,顺其一直向下
p=p->llink;
cout<<p->info; //访问
}
else if(p->rlink != NULL && p->rtag == 0){ //左子树是线索而右子树不是线索
p=p->rlink;
cout<<p->info; //访问
}
else if(p->rlink->rlink != NULL){ //左,右子树都是线索
p=p->rlink->rlink; //顺线索越过根结点(已访问过)
cout<<p->info; //访问
}
else //先序遍历结束
break;
}
}
程序样例如下,首先根据特殊的先根序列构造普通的二叉树,然后对其进行对称序线索化,然后先根序列遍历对称序线索二叉树,得到先根序列,访问某结点的后继结点读者自己给出。输入样例以本文的二叉树为例,
#include <iostream>
#include <stack>
#include <cstring>
#include <cstdio>
#define MAXN 100
#define DataType char
using namespace std;
typedef struct ThrTreeNode* pThrTreeNode;
typedef struct ThrTreeNode* pThrTree;
struct ThrTreeNode{
DataType info;
pThrTreeNode llink,rlink;
int ltag,rtag;
};
void Thread(pThrTree t)
{
stack<pThrTree> s;
pThrTree p = t, pre = NULL;
if(t == NULL) return;
do{
while(p){ //遇到结点压入栈,然后进入其左子树
s.push(p); p=p->llink;
}
p=s.top(); s.pop();
if(pre){
if(pre->rlink == NULL){ //修改前驱结点的右指针
pre->rlink = p;
pre->rtag = 1;
}
if(p->llink == NULL){ //修改该节点的左指针
p->llink = pre;
p->ltag = 1;
}
}
pre = p; p=p->rlink;
}while(!s.empty() || p);
}
void ThreadPreOrder(pThrTree t) //按先序遍历周游中序线索二叉树
{
pThrTree p =t;
if(t == NULL) return;
else cout<<p->info; //先访问线索二叉树根结点
while(p != NULL){
if(p->llink != NULL && p->ltag == 0){ //左子树不是线索时,顺其一直向下
p=p->llink;
cout<<p->info; //访问
}
else if(p->rlink != NULL && p->rtag == 0){ //左子树是线索而右子树不是线索
p=p->rlink;
cout<<p->info; //访问
}
else if(p->rlink->rlink != NULL){ //左,右子树都是线索
p=p->rlink->rlink; //顺线索越过根结点(已访问过)
cout<<p->info; //访问
}
else //先序遍历结束
break;
}
}
pThrTree CreateBinTree(char seq[],int &i,int k){
//创建普通二叉树
if(i>k||seq[i]=='#')
return NULL;
pThrTreeNode p=new struct ThrTreeNode;
if(p!=NULL){
p->info=seq[i];
p->ltag=p->rtag=0; //初始化标志量
i++;
p->llink=CreateBinTree(seq,i,k);
i++;
p->rlink=CreateBinTree(seq,i,k);
return p;
}
return NULL;
}
int main()
{
char seq[MAXN];
scanf("%s",seq);
int k=0;
pThrTree t = CreateBinTree(seq, k, strlen(seq)-1);
Thread(t);
ThreadPreOrder(t);
return 0;
}
INPUT:
ABC##D##EF#GH##I###
OUTPUT:
ABCDEFGHI
另外,中序遍历对称序线索二叉树和构造二叉树的算法见于 http://blog.csdn.net/gnosed/article/details/79542228 。