一.线索二叉树
我们在遍历二叉树时会得到一个线性序列,而在一些应用中我们需要频繁的得到某个元素的前驱或后继,而每次均遍历一遍时间消耗过大,因此提出了线索二叉树的概念,用于在树中储存一条链用以记录这条线性序列,使得我们可以高效的调用某些元素的前驱或后继。
二.实现方法
线索二叉树建立:
一般想法是在二叉树结构中加入两个指针域分别指向前驱后继,但是这样会使结构体的存储密度大大降低,因此在二叉链表的结点中增加两个标志域Ltag, Rtag进而把空指针变成线索:
0 表示 lchild(p) 为指向左孩子的指针
ltag(p)=
1 表示 lchild(p) 为指向直接前驱的线索
0 表示 rchild(p) 为指向右孩子的指针
rtag(p)=
1 表示 rchild(p) 为指向直接后继的线索
同时再设立一个pre指针指向当前结点的前驱,辅助操作使得当前节点的前驱线索指向前驱,前驱的后继线索指向当前结点,由此只需完成一遍遍历就可以建立一个XX线索。当然我们看到建立的过程就是一遍遍历因此不要对仅需一遍遍历的题目建立线索,因为没有必要。
线索二叉树的输出:
为方便起见,一般会在线索二叉树前设立一个头节点,并令其lc指向二叉树根节点,其rc指向最后一次访问的节点,这样建立成的线索二叉树就像一个双向链表,既可以根据后继由前向后遍历,也可以根据前驱有后向前遍历。
三.三种线索二叉树
给出代码之前先说以下建立函数吧,其实三种建立函数都和相应的遍历函数差不太多,就是把遍历操作函数中的输出操作改为判断空指针、空指针设立线索、判断pre(前驱)位置三种操作。下面是具体代码,代码中对三种遍历建立函数部分写明了注释。
1.中序二叉树
/*
中序线索二叉树
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int link = 0;//指针
const int thread = 1;//线索
typedef struct Bintree
{
char data;
struct Bintree *lc, *rc;
int LTag, RTag;
}BinNode, *Bin;
void CreateTree(Bin &T)
{
char ch;
scanf("%c", &ch);
if(ch=='#')
T = NULL;
else
{
T = (Bin)malloc(sizeof(BinNode));
T->data = ch;
T->LTag = T->RTag = link;
CreateTree(T->lc);
CreateTree(T->rc);
}
}
void InThreading(Bin p, Bin &pre)//中序建线索
{
if(p)
{
InThreading(p->lc, pre);
if(!p->lc)//左为空证明无左子连,左为前驱线索
{
p->LTag = thread;
p->lc = pre; //左线索指向前驱pre
}
if(!pre->rc)
{
pre->RTag = thread;
pre->rc = p;//前驱的后继为当前结点
}
pre = p;//保持pre指向p前驱,判断前驱位置
InThreading(p->rc, pre);
}
}
void InorderThreading(Bin &Thrt, Bin T)
{
if(!(Thrt = (Bin)malloc(sizeof(BinNode))))
exit(0);
Thrt->LTag = link;//初始化建立根
Thrt->RTag = thread;
if(!T)//空的话
Thrt->lc = Thrt;
else
{
Thrt->lc = T;
Bin pre = Thrt;
InThreading(T, pre);
pre->rc = Thrt;
pre->RTag = thread;
Thrt->rc = pre;
}
}
void Inthread_out(Bin Thrt)
{
Bin p = Thrt->lc;
while(p != Thrt)//没绕回来
{
while(p->LTag == link)
{
p = p->lc;
}
printf("%c", p->data);
while(p->RTag == thread&&p->rc!=Thrt)
{
p = p->rc;
printf("%c", p->data);
}
p = p->rc;
}
}
void In_out(Bin T)
{
if(T)
{
In_out(T->lc);
printf("%c", T->data);
In_out(T->rc);
}
}
void Destory(Bin &T)
{
T->lc = NULL;
T->rc = NULL;
free(T);
}
int main()
{
Bin T;
Bin Thrt;
CreateTree(T);
In_out(T);
printf("\n");
InorderThreading(Thrt, T);
Inthread_out(Thrt);
Destory(T);
Destory(Thrt);
}
/*
-+a##*b##-c##d##/e##f##
*/
2.先序线索二叉树
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int link = 0;//链
const int thread = 1;//线索
typedef struct Bintree
{
char data;
struct Bintree *lc, *rc;
int LTag, RTag;
}BinNode, *Bin;
void CreateTree(Bin &T)
{
char ch;
scanf("%c", &ch);
if(ch == '#')
T = NULL;
else
{
T = (Bin)malloc(sizeof(BinNode));
T->data = ch;
T->LTag = T->RTag = 0;
CreateTree(T->lc);
CreateTree(T->rc);
}
}
void Pre_out(Bin T)
{
if(T)
{
printf("%c", T->data);
Pre_out(T->lc);
Pre_out(T->rc);
}
}
void PreThreading(Bin T, Bin &pre)//先序建立
{
if(T)
{
int flag = 0;
if(!T->lc)
{
flag = 1;
T->lc = pre;
T->LTag = thread;
}
if(!pre->rc)
{
pre->RTag = thread;
pre->rc = T;
}
pre = T;
if(!flag)//如果对左子进行了操作,证明左子原来为空指针,则不需要再操作
PreThreading(T->lc, pre);
PreThreading(T->rc, pre);
}
}
void PreorderThreading(Bin &Thrt, Bin T)
{
if(!(Thrt = (Bin)malloc(sizeof(BinNode))))
exit(0);
Thrt->LTag = link;
Thrt->RTag = thread;
if(!T)
Thrt->lc = Thrt;
else
{
Thrt->lc = T;
Bin pre = Thrt;
PreThreading(T, pre);
pre->RTag = thread;
pre->rc = Thrt;
Thrt->rc = pre;
}
}
void Prethread_out(Bin Thrt)
{
Bin p = Thrt->lc;
while(p!=Thrt)
{
while(p->LTag == link)
{
printf("%c", p->data);
p = p->lc;
}
printf("%c", p->data);
while(p->RTag == thread&&p->rc!=Thrt)
{
p = p->rc;
printf("%c", p->data);
}
if(p->rc!=Thrt)
p = p->lc;
else
p = p->rc;
}
}
void Destory(Bin &T)
{
T->lc = NULL;
T->rc = NULL;
free(T);
}
int main()
{
Bin T;
Bin Thrt;
CreateTree(T);
Pre_out(T);
printf("\n");
PreorderThreading(Thrt, T);
Prethread_out(Thrt);
Destory(T);
Destory(Thrt);
}
3.后序线索二叉树
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int link = 0;
const int thread = 1;
typedef struct BinTree
{
char data;
struct BinTree *lc, *rc;
int LTag, RTag;
}BinNode, *Bin;
void CreateTree(Bin &T)
{
char ch;
scanf("%c", &ch);
if(ch == '#')
T = NULL;
else
{
T = (Bin)malloc(sizeof(BinNode));
T->data = ch;
T->LTag = T->RTag = link;
CreateTree(T->lc);
CreateTree(T->rc);
}
}
void Post_out(Bin T)
{
if(T)
{
Post_out(T->lc);
Post_out(T->rc);
printf("%c", T->data);
}
}
void Postthreading(Bin T, Bin &pre)//T回溯之后pre是更改以后的值
{//后序建立
if(T)
{
Postthreading(T->lc, pre);
Postthreading(T->rc, pre);
if(!T->lc)
{
T->LTag = thread;
T->lc = pre;
}
if(!pre->rc||pre->RTag == link)//涉及后继为父节点的情况
{//父节点左右指针并不为空,需要另行操作,将原来指针变为线索
pre->RTag = thread;
pre->rc = T;
}
pre = T;
}
}
void Postorderthreading(Bin &Thrt, Bin T)
{
if(!(Thrt = (Bin)malloc(sizeof(BinNode))))
exit(0);
Thrt->LTag = link;
Thrt->RTag = thread;
if(!T)
Thrt->lc = Thrt;
else
{
Thrt->lc = T;
Bin pre = Thrt;
Postthreading(T, pre);
pre->rc = Thrt;
pre->RTag = thread;
Thrt->rc = pre;
}
}
void Postthread_out(Bin Thrt)
{
Bin p = Thrt->lc;
while(p->lc&&p->LTag == link)
{
p = p->lc;
}
printf("%c", p->data);
while(p!=Thrt->lc)
{
while(p->RTag == thread&&p!=Thrt->lc)
{
p = p->rc;
printf("%c", p->data);
}
}
}
void Destory(Bin &T)
{
T->lc = NULL;
T->rc = NULL;
free(T);
}
int main()
{
Bin T;
Bin Thrt;
CreateTree(T);
Post_out(T);
printf("\n");
Postorderthreading(Thrt, T);
Postthread_out(Thrt);
Destory(T);
Destory(Thrt);
}