二叉树线索化
背景:以二叉链实现的二叉树中,存储空间的利用效率较低。假设有一棵有n个结点的二叉链实现的二叉树,则其公有2n个指针域,而其中只有n-1个分支结点(除了1个根结点以外,其他都是分支结点),因为每个分支结点都有一个指针域对应,因此有:2n - (n-1) = n+1个指针域空置,为了提高存储空间的利用率并且提高二叉树遍历的速度,因此需要对二叉树进行线索化,用空置的指针域链接相应的前驱和后继元素。
基本思路:在遍历过程中,各个前驱、后继会按照遍历顺序相应被访问,因此采取递归遍历二叉树,并且在遍历过程中链接各个结点。
0. 线索二叉树结点类型声明:
typedef struct node
{
ElemType data; //自定义类型别名
int ltag,rtag; //标志位,值为1表示指针域为线索,指向前驱或后继结点;为0表示指向孩子结点
struct node *lchild;
struct node *rchild;
}TagBTNode;
1. 前序线索化
- 线索化算法:
注意:因为是前序遍历,所以先线索化根结点,因此在线索化左右子树的时候,根结点的左右指针域可能指向前驱后继而不是孩子,因此在线索化某个根结点的左右子树之前需要判断是前驱后继还是孩子
//递归前序线索化二叉树算法
void PreThread(TagBTNode *btree_p)
{
if(btree_p == NULL)
return ;
else
{
if(btree_p->lchild == NULL)
{
btree_p->lchild = pre_p;
btree_p->ltag = 1;
}
else
btree_p->ltag = 0;
if(pre_p->rchild == NULL) //pre_p为全局变量,指向btree_p的指向结点的前驱
{
pre_p->rchild = btree_p;
pre_p->rtag = 1;
}
else
pre_p->rtag = 0;
pre_p = btree_p;
//这一步需要注意:因为是前序遍历,所以每棵树或子树的根结点先被线索化,因此在线索化某个根结点的子树之前需要判断其子树根结点是孩子结点还是被线索指向的后继结点
if(btree_p->ltag == 0) //如果是孩子结点,则对其线索化
PreThread(btree_p->lchild);
if(btree_p->rtag == 0)
PreThread(btree_p->rchild);
}
}
- 创建线索二叉树算法:
//定义前驱指针
TagBTNode *pre_p;
//创建算法
TagBTNode * CreatePreThread(TagBTNode *btree_p)
{
//创建一个头结点root指向二叉树的根结点
TagBTNode *root = (TagBTNode *)malloc(sizeof(TagBTNode));
root->ltag = 0;
root->rtag = 1;
root->rchild = btree_p;
if(btree_p == NULL)
root->lchild = root;
else
{
root->lchild = btree_p;
pre_p = root;
PreThread(btree_p);
pre_p->rchild = root;
pre_p->rtag = 1;
root->rchild = pre_p;
}
return root;
}
- 线索遍历输出算法:
void PreThreadTravel(TagBTNode *root)
{
TagBTNode *node_p = root->lchild;
while(node_p != root)
{
printf("%c", node_p->data);
while(node_p->rtag == 1 && node_p->rchild != root)
{
node_p = node_p->rchild;
printf("%c", node_p->data);
}
if(node_p->ltag == 0)
node_p = node_p->lchild;
else
node_p = node_p->rchild;
}
}
2. 中序线索化:
- 线索化算法:
注意:因为先线索化左子树,再线索化根结点,并且在线索化右子树之前,根结点没有被作为前驱,因此在线索化左右子树的时候,不需要进行判断
void InThread(TagBTNode *btree_p)
{
if(btree_p == NULL)
return ;
else
{
InThread(btree_p->lchild);
if(btree_p->lchild == NULL)
{
btree_p->lchild = pre_p;
btree_p->ltag = 1;
}
else
btree_p->ltag = 0;
if(pre_p->rchild == NULL)
{
pre_p->rchild == btree_p;
pre_p->rtag = 1;
}
else
pre_p->rtag = 0;
pre_p = btree_p;
InThread(btree_p->rchild);
}
}
- 创建线索二叉树算法:
同前序创建线索二叉树
- 线索遍历输出:
void InThreadTravel(TagBTNode *root)
{
TagBTNode *node_p = root->lchild;
while(node_p != root)
{
//找到最左结点——中序遍历的开始结点
while(node_p->ltag == 0)
node_p = node_p->lchild;
printf("%c", node_p->data);
while(node_p-rtag == 1 && node_p->rchild != root)
{
node_p = node_p->rchild;
printf("%c", node_p->data);
}
node_p = node_p->rchild;
}
}

本文深入探讨了二叉树的线索化技术,包括前序和中序线索化的具体算法,以及如何创建和遍历线索二叉树。通过递归方式,将二叉树中未使用的指针域转化为指向前后驱节点的线索,从而提高存储效率和遍历速度。
1745

被折叠的 条评论
为什么被折叠?



