一、引入
首先我们来聊一聊二叉树相较于别的结构有什么优点和缺点
优点:
数组的话搜索比较便捷,可以直接用下标进行查找,但是如果进行了删除和插入的操作就比较麻烦
链表就恰好相反,插入和删除操作比较简单,但是查找起来比较慢。
而二叉树则是很好的中和了这两种结构,既有数组的优点有包含链表的优点。
缺点:
在二叉树的实现中往往会浪费掉许多的指针域,而对于一个有着n个节点的二叉链表,每个节点都有左右两个孩子的指针域,一共是有2n个指针域的,但其实是存在有n+1个空指针域,它们都存储着NULL,所以就造成了很大的浪费。
还有一个点就是,在二叉树中我在做遍历的时候,我是不知道每个节点它的前驱和后继是谁,如果我们想知道的话必须要从头到尾来遍历一遍,非常麻烦!
二、线索二叉树的原理和实现
我们把指向前驱和后继的指针成为线索,加上线索的二叉链表称为线索链表,相对应的二叉树就称为线索二叉树
---大话数据结构
如何去实现线索二叉树呢?
在对一颗二叉树进行中序遍历的时候,将所有节点的rchild,如果它为空就修改成它的后继节点。然后再将这颗二叉树所有为空的lchild改为它的前驱节点。
前驱:在这个遍历中排名在你前面一位的叫你的前驱结点
后继:在这个遍历中排母在你后面一位的叫你的后继结点
这里还有一个问题,那我应该怎么才能判断出来某节点的lchild指向的是左孩子还是前驱节点呢?
所以我们这里新加两个标志域ltag和rtag,来判断这个节点的左/右指针域是指向的左/右孩子还是前驱/后继 ,为1就是指针被线索化了,为0就是指向的孩子。
为什么要对树进行线索化呢?有什么意义?
就是可以在不使用递归和栈的情况下更快地对树进行遍历,这样可以提高算法的效率,也就是说,我们将会使用线索来代替递归的功能,在原本不得不用递归来获得某一结点后继节点的情况下,我们使用线索的功能来解除这样的限制。
具体实现线索二叉树
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef enum{Link,Thread} PointerTag;
typedef struct BiThrNode
{
char data;
struct BiThrNode* lchild, * rchild;
PointerTag ltag;
PointerTag rtag;
} BiNode,*BiTree;
BiTree pre = NULL;//声明全局变量,表示在中序遍历过程中当前节点的前驱
void CreatTree(BiTree* t)
{
char ch;
scanf("%c", &ch);
getchar();
if (ch == '0')
{
*t = NULL;
return;
} //用户输入0代表当前节点的左/右孩子没有
else
{
*t = (BiTree)malloc(sizeof(BiNode));
(*t)->data = ch;
printf("请输入左节点:\n");
CreatTree(&(*t)->lchild);
printf("请输入右节点:\n");
CreatTree(&(*t)->rchild);
}
//利用前序遍历来创建一个普通的二叉树
}
void InThreading(BiTree t)//对二叉树进行中序线索化
{
if (t == NULL) return;
InThreading(t->lchild);//对左孩子进行线索化
if (t->lchild == NULL)//如果左孩子为空了
{
t->ltag = Thread; //就将它的左孩子进行线索化,等于前驱
t->lchild = pre;
}
if (pre != NULL && pre->rchild == NULL)
//因为此时的t节点还没有访问到它的后继结点,就只能对它的前驱结点pre的右指针进行判断
//如果为空,那么它就是pre的后继结点,可以举个例子进行模拟一下
//就是因为中序遍历的性质,先将左结点遍历一遍再遍历右结点,自己模拟一遍就知道了
{
pre->rtag = Thread;
pre->rchild = t;
}
pre = t;//始终保持pre是p的前驱
InThreading(t->rchild); //对右孩子进行线索化
}
void InOrderThreading(BiTree t)//中序遍历线索化二叉树
{
while (t != NULL)
{
while (t->ltag==Link)//循环到中序序列第一个结点
{
t = t->lchild;
}
printf("%c ", t->data);
while (t->rtag==Thread)
{
t = t->rchild;
printf("%c ", t->data);//打印后继
}
t = t->rchild;
}
}
main()
{
BiTree t = NULL;
CreatTree(&t);
InThreading(t);
InOrderThreading(t);
}