#include<iostream>
#include<time.h>
#include<Windows.h>
using namespace std;
#define NUM 100
#define BUSY 0
#define REST 1
#pragma warning(disable:4996)
typedef struct node
{
char data;
struct node* lchild;
struct node* rchild;
int lcount;
int rcount;
}*TNode, Tnode;
void createhead(TNode &p);//初始化表头
void Createtree(TNode &Tree);//建立二叉树
void Endnode(TNode &T, TNode &t);//求出二叉树最后一个结点
void Linktree(TNode Tree,TNode &p);//线索化二叉树
/*关于线索化二叉树函数中Tree和p的关系:以p的视角来看p永远是Tree的前驱,Tree永远是p的后继,所以在p的右孩子为空或者Tree的左孩
子为空时,让p->rchild=Tree,Tree->lchild=p,用这样的方式以中序遍历的方式依次为每个节点寻找它的前驱和后继,以此完成二叉树的线
索化*/
void printtree(TNode Head);//遍历线索二叉树(非递归)
int main()
{
TNode Tree; //创建二叉树根节点
TNode p; //创建线索化二叉树的跟踪节点
TNode head=new Tnode; //初始化头结点
createhead(p);
cout << "请以先序遍历录入二叉树:";
Createtree(Tree);
head->lchild = Tree; //让头结点的左孩子指向中序遍历的第一个节点
Linktree(Tree,p);
Endnode(Tree, head);
cout << "中序遍历(非递归)打印此二叉树结果为:";
printtree(head);
return 0;
}
void createhead(TNode &p)//初始化表头
{
p = new Tnode;
p->data = 'Z';
p->lcount = p->rcount = -1;
p->lchild = p->rchild = NULL;
}
void Createtree(TNode &Tree)//建立二叉树
{
char ch;
cin >> ch;
if (ch == '#')Tree = NULL;
else
{
Tree = new Tnode;
Tree->data = ch;
Tree->lcount = BUSY;
Tree->rcount = BUSY;
Createtree(Tree->lchild);
Createtree(Tree->rchild);
}
}
void Endnode(TNode &T,TNode &t)//求出二叉树中序遍历最后一个结点,并让最后一个结点的右孩子指向表头
{
TNode p = T;
while (p->rchild)p = p->rchild;
p->rchild=t;
}
void Linktree(TNode Tree,TNode &p)//线索化二叉树
{
if (Tree)
{
Linktree(Tree->lchild,p);
if (Tree->lchild == NULL)//因为无法预知后继,所以给当前节点寻找已知的前驱(在Tree->lchild == NULL的情况下)
{
Tree->lcount = REST;
Tree->lchild = p;
}
if (p->rchild == NULL)//在产生后继后,用p代替刚才的"当前节点",来给当前节点寻找后继(在p->rchild == NULL)
{
p->rcount = REST;
p->rchild = Tree;
}
p = Tree;
Linktree(Tree->rchild,p);
}
}
void printtree(TNode Head)//遍历线索二叉树(非递归)
{
TNode p = Head->lchild;
while (p != Head)
{
while (p->lcount == BUSY)//找到子树部分的最左结点,即子树部分中序遍历的第一个结点
{
p = p->lchild;
}
cout <<p->data;
while (p->rcount == REST && p->rchild != Head)
{
p = p->rchild;
cout << p->data;//由于线索化过后,只要rcount==REST,就一直遍历右孩子,直到找到的结点有实际右孩子
}
p = p->rchild; //进入子树的右子树
}
}
这是演示示例的逻辑结构图,在本例中以编译器输入#为结束符号,即表示指向空
上图中蓝色连接线是未线索化之前的逻辑结构,加上橙色连接线后是线索化过程中进行的结点前驱后继的连接结果
所以在编译器中的输入应为:ABC##DE##F##G#HI###
下图是对应代码的运行结果
【注】:线索二叉树的好处就是在需要多次遍历二叉树或者寻找二叉树相应结点的前驱后继时,利用这种逻辑结构可以在遍历时不采用递归策略,从而减少对堆内存的消耗并且可以快速得出每个结点的前驱后继