二叉树的结点结构定义如下:
lchild | ltag | data | rtag | rchild |
ltag=0 时lchild指向左儿子;ltag=1 时lchild指向前驱;rtag=0 时rchild指向右儿子;rtag=1 时rchild指向后继。
步骤:
先使用前序遍历建立一个二叉树,先将他们的 ltag 和 rtag 设为0,默认他们都有左右孩子,在第二遍中序遍历的时候如果 lchild 为 NULL 则指向这个结点的前驱,rchild 为 NULL 则指向这个结点的后继。
建立线索:
二叉树建立完成之后,在中序遍历的过程中建立线索。此时需要定义一个指向该结构体的指针 pre (该指针为全局变量),并让这个指针动态的始终指向上一个结点。
线索二叉树建立完毕后如下图所示,黑线代表指向左右孩子,蓝线代表指向该点的前驱结点,红线代表指向该点的后继结点。
具体代码实现(C语言):
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
typedef int Status;
typedef struct BinTNode
{
ElemType data;
Status ltag, rtag;
struct BinTNode *lchild, *rchild;
} BinTNode, *BinTree;
// pre 指向上一个访问过的结点
BinTree pre;
/*
Status 为1时表示指向前驱或后继结点
为0时表示指向孩子结点
*/
void createBinTree(BinTree *root)
{
char c;
scanf("%c", &c);
if ( '^' == c )
{
(*root) = NULL;
}
else
{
(*root) = (BinTree)malloc(sizeof(BinTNode));
(*root)->data = c;
(*root)->ltag = 0;
(*root)->rtag = 0;
createBinTree(&(*root)->lchild);
createBinTree(&(*root)->rchild);
}
}
void middleOrderTraversal(BinTree root)
{
if (root)
{
middleOrderTraversal(root->lchild);
if ( !root->lchild )
{
root->ltag = 1;
root->lchild = pre;
}
if ( !pre->rchild )
{
pre->rtag = 1;
pre->rchild = root;
}
pre = root;
middleOrderTraversal(root->rchild);
}
}
void initPre(BinTree *p, BinTree root)
{
*p = (BinTree)malloc(sizeof(BinTNode));
(*p)->ltag = 0;
(*p)->rtag = 1;
(*p)->rchild = *p;
if ( !root )
{
(*p)->lchild = *p;
}
else
{
(*p)->lchild = root;
pre = *p;
middleOrderTraversal(root);
pre->rchild = *p;
pre->rtag = 1;
(*p)->rchild = pre;
}
}
int main(void)
{
BinTree p, root = NULL;
printf("按照前序遍历输入二叉树结点值:");
createBinTree(&root);
initPre(&p, root);
return 0;
}
运行结果:
按照前序遍历输入二叉树结点值: ABC^^D^^E^F^^
注:符号 ^ 表示该结点的左孩子或右孩子为 NULL。
线索二叉树是否建立成功我们需要在debug中查看一下,如下图:
C结点的 rtag 为 1 说明该节点没有右孩子,则 rchild 应指向它的后继结点 B。
经检查线索二叉树建立完成。