1.结点结构
struct ThreadNode
{
DataType data;
ThreadNode *lchild,*rchild;
int itag,rtag;
};
2.线索二叉树
(1)中序线索二叉树
类的声明:
class ThreadBiTree
{
private:
ThreadNode *root;
public:
ThreadBiTree();
~ThreadBiTree();
ThreadNode *next(ThreadNode *p);//查找p的后继
void inOrder();
private:
ThreadNode *creat(ThreadNode *bt);
void inThread(ThreadNode *p);//线索化二叉树
};
大致逻辑【一步一步来的逻辑】:
1.p左孩子为空,设置前驱线索:【pre为空,不操作】
p的左孩子不为空,不操作
p->ltag=1;
p->lchild=pre(NULL);
2.pre右孩子为空,设置后继线索
pre右孩子不为空,不操作
pre->rtag=1;
pre->rchild=p;
3.用pre保存 p的内容,p指向下一个结点,也就是p分左孩子
实际上的逻辑就是【快速写的逻辑】
1.判断ltag和rtag和线索
如果一个结点有左孩子,那么ltag就为0,没有左孩子就为1
当ltag为1时,表示结点的左孩子那个地方的指针指向空,那么我们就建立
起一个联系,指向前驱(中序排列的后面一个)
如果一个结点有右孩子,那么rtag就为0,否则为1
当rtag为1时,表示结点的右孩子那个地方的指针指向空,那么我们就建立
起一个联系,指向后驱
中序线索二叉树的建立
void ThreadBiTree::inThread(ThreadNode *p)
{
if(p==NULL)
{
return;
}
inThread(p->lchild);
if(p->lchild==NULL)
{
p->ltag=1;
p->lchild=pre;
}
if(pre!=NULL&&pre->rchild==NULL)
{
pre->rtag=1;
pre->rchild=p;
}
pre=p;
inThread(p->rchild);
}
如何定义pre
1.在线索二叉树中添加
class
{
private:
ThreadNode *pre;};
ThreadBiTree()
{
pre=NULL;
root=creat(root);
inThread(root);
}
2.全局 变量
ThreadBiTree
{
static ThreadNode *pre=NULL;
}
中序线索链表查找后继
我们来想一下前驱和后继是怎么查找的
1.首先如果没有左右孩子的话,那么他的左右孩子的指针
就是指向他的前驱和后继
2.如果他的右孩子为空,那么他就是指向后继
如果不为空,那么根据中序遍历,你就要找到右子树的最左边的那一个结点
如果左孩子为空那么就是指向前驱
如果不为空,那么根据中序遍历,你就要找到左子树的最右边的那一个结点
ThreadNode *ThreadBiTree::next(ThreadNode*p)
{
if(p->rtag==1)
{
q=p->rchild;
}
else
{
q=p->rchild;
while(q->ltag==0)
{
q=q->lchild;
}
}return q;
}
中序线索链表的遍历算法
void ThreadBiTree::inOrder()
{
ThreadBode *p;
if(root==NULL)
{
return;
}
p=root;
while(p->ltag==0)//查找中序遍历中的第一个结点
{
p=p->lchild;
}
visit(p->data);//访问第一个结点
while(p->rchild!=NULL)
/*这个rchild是表示后继结点,
如果有右孩子那么就指向右孩子,但是这个右孩子不一定是后继
如果没有右孩子,那么rchild就直接指向后继
*/
{
p=next(p);
visit(p->data);
}
}
总代码
/*定义中序线索二叉树
运行范例:
abd#g###ce##f## (教材PPT的例子)
基本的逻辑是:首先按照前序的顺序创建一颗二叉树,然后
将ltag和rtag赋初值,之后在将二叉树转化成线索二叉树(利用左孩子和右孩子中的
空指针)
将他转化从线索二叉树只需要一个函数,然后以中序遍历的方式去显示线索链表就需要两个函数
因为有两种情况
1.后序直接可以找到
2.后序不能直接找到
所以有一个找后序的函数和一个显示函数
*/
#include<iostream>
#include<stdio.h>
using namespace std;
struct ThreadNode{
char data;
ThreadNode *lchild, *rchild;
int ltag, rtag;
};
class ThreadBiTree{
private:
ThreadNode *root;//指向线索链表的头指针
public:
ThreadNode *pre;
ThreadBiTree() {//构造函数,建立中序线索链表
pre=NULL;
root = NULL;
root = creat(root);
inThread(root);
}
~ThreadBiTree(); //析构函数,释放各结点的存储空间
ThreadNode *next(ThreadNode *p); //查找p的后继
void inOrder(); //中序遍历线索链表
private:
ThreadNode *creat(ThreadNode *bt);
void destroy(ThreadNode *p); //线索化,由构造函数调用
void inThread(ThreadNode *p); //线索化,由构造函数调用
};
//create函数创建二叉树
ThreadNode *ThreadBiTree::creat(ThreadNode *bt){
//在此处填写创建线索二叉树的代码
char ch;
cin>>ch;
if(ch=='#')
{
bt=NULL;
}
else
{
bt=new ThreadNode ;
bt->data=ch;
bt->ltag=0;
bt->rtag=0;
bt->lchild=creat(bt->lchild);
bt->rchild=creat(bt->rchild);
}
return bt;
}
//实现二叉树线索化,这个函数由构造函数调用
void ThreadBiTree::inThread(ThreadNode *p){
//在此处填写建立二叉树线索化的代码,注意,这个函数跟其他函数不同,它 的函数头可以修改,注意检查大括号是否匹配
if(p==NULL)
return;
inThread(p->lchild);
if(p->lchild==NULL)
{
p->ltag=1;
p->lchild=pre;
}
if(pre!=NULL&&pre->rchild==NULL)
{
pre->rtag=1;
pre->rchild=p;
}
pre=p;
inThread(p->rchild);
}
//查找p的后继
ThreadNode* ThreadBiTree::next(ThreadNode *p){
ThreadNode *q;
if(p->rtag==1)
{
q=p->rchild;
}
else
{
q=p->rchild;
while(q->ltag==0)
{
q=q->lchild;
}
}
return q;
}
//中序遍历线索链表
void ThreadBiTree::inOrder(){
//在此处填写中序遍历线索二叉树的代码
ThreadNode *p;
if(root==NULL)
{
return;
}
p=root;
while(p->ltag==0)//查找中序遍历中的第一个结点
{
p=p->lchild;
}
cout<<p->data;//访问第一个结点
while(p->rchild!=NULL)
/*这个rchild是表示后继结点,
如果有右孩子那么就指向右孩子,但是这个右孩子不一定是后继
如果没有右孩子,那么rchild就直接指向后继
*/
{
p=next(p);
cout<<p->data;
}
}
ThreadBiTree::~ThreadBiTree(){
ThreadNode *q,*p;
p=root;
while(p->ltag==0)
{
p=p->lchild;
}
q=p;
while(p->rchild!=NULL)
{
cout<<"delete "<<p->data<<endl;
p=next(p);
delete q;
q=p;
}
cout<<"delete "<<p->data<<endl;
delete p;
}
int main(){
ThreadBiTree tree;
cout << "Inorder:";
tree.inOrder();
cout << endl << "Inorder finished. Calling destructer..."<<endl;
return 0;
}