祖国70岁生日快乐
学习不停
线索二叉树:普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得若将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树。
总结起来线索二叉树其实就是利用节点空指针来指向前驱节点或后继节点。总的来说能根据任一节点遍历整棵树。
1)若结点有左子树,则lchild指向其左孩子;
否则, lchild指向其直接前驱(即线索);
2)若结点有右子树,则rchild指向其右孩子;
否则, rchild指向其直接后继(即线索) 。
为了避免混淆,每个节点增加两个标志域
LTag :若 LTag=0, lchild域指向左孩子;
若 LTag=1, lchild域指向其前驱。
RTag :若 RTag=0, rchild域指向右孩子;
若 RTag=1, rchild域指向其后继。
下图为二叉树中序遍历,
节点B,无左孩子(lchild为空),LTag标记为1,lchild指向A,
节点C,无左右孩子(lchild、rchild为空),LTag与RTage标记为1,lchild指向B,rchild指向后继,此处后继无节点,则回到开始,可以是A,也可以加一个头节点(root)。
节点D,无右孩子(rchild为空),RTag标记为1,rchild指向A或(root)。
节点E,无左右孩子(lchild、rchild为空),LTag与RTage标记为1,lchild指向A,rchild指向前驱D。
这里重点讲下中序,其它序列只是顺序不同,线索原理是一样的的。
线索:指向结点前驱和后继的指针
线索链表:加上线索二叉链表
线索二叉树:加上线索的二叉树(图形式样)
线索化:对二叉树以某种次序遍历使其变为线索二叉树的过程
注:此图中序遍历结果为: H, D, I, B, E, A, F, C, G
#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
// 定义线索二叉树类型
typedef struct Tree {
int data, Ltag, Rtag; // 数据域 左右标记
struct Tree *LChild, *RChild; // 左孩子指针 右孩子指针
}Tree,*Trees;
Trees pre = NULL; // 全局指针
// 初始化二叉树,只有一个根节点,无左右孩子
void InitBiTree(Trees *root){
*root = (Trees)malloc(sizeof(Tree));
(*root)->LChild = (*root)->RChild = NULL;
(*root)->Ltag = (*root)->Rtag = 0;
}
// 创建二叉树
void CreateBiTree(Trees &root) {
int ch;
scanf_s("%d", &ch); // 从键盘输入数据域值
if (ch == 0)
root = NULL;
else
{
root = (Trees)malloc(sizeof(Tree)); // 开辟空间存储数据ch
root->data = ch;
root->LChild = root->RChild = NULL;
root->Ltag = root->Rtag = 0;
CreateBiTree(root->LChild);
CreateBiTree(root->RChild);
}
}
// 添加线索
void InsertLineTree(Trees &root) {
if (root != NULL)
{
InsertLineTree(root->LChild); // 线索化左子树
if (root->LChild == NULL)
{
root->Ltag = 1;
root->LChild = pre; //设置前驱线索
}
if (pre != NULL && pre->RChild == NULL)
{
pre->RChild = root;
pre->Rtag = 1;
}
// 当前访问节点为下一个访问节点的前驱
pre = root;
// 线索公右子树
InsertLineTree(root->RChild);
}
}
// 创建头结点
Trees InOrderThread(Trees &rt) {
Trees throot;
if (!(throot = (Trees)malloc(sizeof(Tree))))
{
printf("创建头结点失败.\n\n");
exit(1);
}
throot->Ltag = 0; // 等于0 指向左孩子 1
throot->Rtag = 1; // 等于1 指向遍历的前驱 2
throot->RChild = throot; // 右回指针,指向自己(头结点) 3
if (!throot)
throot->LChild = throot; // 如二叉树为空,建立左回指针(也就是指向头结点)
else
{
throot->LChild = rt; // 也就是二叉村的根
pre = throot; // 指向头结点
InsertLineTree(rt); // 为二叉树加线索
pre->RChild = throot;
pre->Rtag = 1;
throot->RChild = pre;
}
return throot;
}
// 中序遍历查找前驱
void InPre(Trees root) {
Trees q = NULL;
if (root->Ltag == 1)
pre = root->LChild;
else
{
for (q = root->LChild; q->Rtag == 0; q = q->RChild)
pre = q;
}
if (pre)
printf("中序遍历找到前驱为:%d\n", pre->data);
else
printf("中序遍历无前驱.\n");
}
// 中序遍历查找后继
void InNext(Trees root)
{
Trees q = NULL;
if (root->Rtag == 1)
pre = root->RChild;
else
{
for (q = root->RChild; q->Ltag == 0; q = q->LChild)
pre = q;
}
if (pre)
printf("中序遍历查找到后继为:%d\n",pre->data);
else
printf("中序遍历无后继.\n");
}
// 中序遍历查找线索二叉树上的第一结点
Trees InFirst(Trees root) {
Trees p = root;
if (!p)
return 0;
while (p->Ltag == 0)
p = p->LChild;
return p;
}
// 中序遍历线索二叉树
void TInOrder(Trees &throot) {
Trees p;
p = throot->LChild;
while (p != throot) {
while (p->Ltag == 0)
p = p->LChild;
printf("%d ", p->data);
while (p->Rtag == 1 && p->RChild != throot)
{
p = p->RChild;
printf("%d ",p->data);
}
p = p->RChild;
}
printf("\n\n");
}
int main()
{
Trees root = NULL;
printf("创建线索二叉树,当用户输入0时结束操作.\n\n");
CreateBiTree(root);
Trees throot; // 头结点
throot = InOrderThread(root);
TInOrder(throot); // 中序遍历
InPre(root); // 中序查找前驱
InNext(root); // 中序查找后继
Trees bt = InFirst(root); // 中序遍历线索二叉树的第一结点
printf("中序遍历线索二叉树的第一个结点为:%d\n",bt->data);
system("pause");
return 0;
}