提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
二叉树作为一种新的存储结构同时兼具了顺序表存储随机存取和链表方便增删的特点,被广泛运用于文件管理系统和数据库系统之中,于此同时,二叉树也有部分可以优化的地方,因为顺序二叉树相较于顺序表存储效率不及后者,链表二叉树相较于链表,读取效率不及后者。
为了使得二叉树拥有更高的存储效率以及更快的读取效率,线索二叉树则应运而生。
线索二叉树的实现方式根据二叉树的遍历特点可以基础的分为中序线索化二叉树以及前序和后序,本文介绍中序线索化二叉树。
一、线索二叉树的结构
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, * rchild;
int ltag, rtag;
} ThreadNode, * ThreadTree;
线索二叉树的通用存储结构包含数据域,左右子树指针,以及线索标记
二、线索二叉树的线索生成
1.定义全局变量
线索化二叉树的时候需要定义一个前指针pre,使其用于指向上一个节点 ,一开始指向NULL
ThreadNode *pre = NULL;
2.中序线索化二叉树
首先定义指针T,让T指针采用递归的方式中序遍历二叉树的各个节点,然后再对遍历到的每一个节点进行线索化,线索化的逻辑:若该节点没有左子树,则将其做指针线索化指向上一个节点,若上一个节点的右子树为空,则使其右指针指向当前节点,于此同时不要忘记将该节点指针标记为线索。
void InThread(ThreadTree &T, ThreadNode *&pre) {
if (T != NULL) {
if (T->ltag == 0)
InThread(T->lchild, pre);
if (T->lchild == NULL) {
T->lchild = pre;
T->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = T;
pre->rtag = 1;
}
pre = T;
if (T->rtag == 0)
InThread(T->rchild, pre);
}
}
3.在对最后一个节点处理时,需要将其右指针线索化
void CreateInThread(ThreadTree T) {
if (T != NULL) {
InThread(T, pre);
if (pre->rchild = NULL) // 处理遍历的最后一个结点
pre->rtag = 1;
}
}
三、找头节点与p节点的后继节点
该步骤是为了对后续节点的中序遍历做铺垫
在中序遍历之中,头节点是二叉树左边的最下方节点
ThreadNode *FirstNode(ThreadNode *p) {
while (p->ltag == 0)
p = p->lchild;
return p;
}
在中序遍历中,
若p->rtag=1,则p->rchild即为后继节点。
若p->rtag=0,p节点的右子树中中序遍历中的第一个节点即为p节点的后继节点。
ThreadNode *NextNode(ThreadNode *p) {
if (p->rtag == 1)
return p->rchild;
else
return FirstNode(p->rchild);
}
四、遍历中序线索化二叉树(非递归)
将指针T赋值给指针p,指针p传入到寻找头节点的功能函数中,从而找到头节点,若指针p不为空则不断执行寻找下一个节点,并将指针p传入visit访问节点功能函数中。
void InOrder(ThreadNode *T) {
for (ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p))
visit(p);
}
五、汇总:
#include <iostream>
typedef int ElemType;
// 线索二叉树(链式存储)
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, * rchild;
int ltag, rtag; // 左右线索标志(有孩子结点时为0,有线索时为1)
} ThreadNode, * ThreadTree;
bool CreateTree(ThreadTree &T, ElemType *datagroup, int length);
bool PreTree(ThreadTree &T, ElemType *datagroup, int length, int &i);
void InThread(ThreadTree &T, ThreadNode *&pre);
void CreateInThread(ThreadTree T);
ThreadNode *FirstNode(ThreadNode *p);
ThreadNode *NextNode(ThreadNode *p);
void InOrder(ThreadNode *T);
void visit(ThreadNode *p);
ThreadNode *pre = NULL;
int main() {
ThreadTree T1;
ElemType datagroup[] = { 1, 2, 4, -1, -1, 5, -1, -1, 3, 6, -1, 7, -1, -1, -1 };
CreateTree(T1, datagroup, sizeof(datagroup) / sizeof(datagroup[0]));
CreateInThread(T1);
InOrder(T1);
std::cout << std::endl;
return 0;
}
bool CreateTree(ThreadTree &T, ElemType *datagroup, int length) {
int i = 0;
return PreTree(T, datagroup, length, i);
}
bool PreTree(ThreadTree &T, ElemType *datagroup, int length, int &i) {
if (i >= length || datagroup[i] == -1) {
T = NULL;
i++;
return true;
}
T = (ThreadNode *)malloc(sizeof(ThreadNode));
if (T == NULL)
return false;
T->data = datagroup[i++];
T->ltag = 0;
T->rtag = 0;
return PreTree(T->lchild, datagroup, length, i) && PreTree(T->rchild, datagroup, length, i);
}
/*==================================================================*/
void InThread(ThreadTree &T, ThreadNode *&pre) {
if (T != NULL) {
if (T->ltag == 0)
InThread(T->lchild, pre);
if (T->lchild == NULL) {
T->lchild = pre;
T->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = T;
pre->rtag = 1;
}
pre = T;
if (T->rtag == 0)
InThread(T->rchild, pre);
}
}
void CreateInThread(ThreadTree T) {
if (T != NULL) {
InThread(T, pre);
if (pre->rchild = NULL)
pre->rtag = 1;
}
}
/*==================================================================*/
ThreadNode *FirstNode(ThreadNode *p) {
while (p->ltag == 0)
p = p->lchild;
return p;
}
ThreadNode *NextNode(ThreadNode *p) {
if (p->rtag == 1)
return p->rchild;
else
return FirstNode(p->rchild);
}
void InOrder(ThreadNode *T) {
for (ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p))
visit(p);
}
void visit(ThreadNode *p) {
std::cout << p->data << " ";
}
运行结果截图: