二叉树遍历及线索化算法
部分参考严蔚敏数据结构一书
实现:
1.先序创建BiTree二叉树:
void Create_BiTree(BiTree &rt)
2.先序遍历:void preOrder(BiTree rt)
3.层级遍历:Status level(BiTree T)
4.中序遍历BiThrNode二叉树T2,并将其中序线索化:
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T)
5.中序遍历并输出结果:
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e))
代码如下:
#include <iostream>
#define OK 1
#define ERROR 0
using namespace std;
#define MAXSIZE 100
typedef char TElemType;
typedef int Status;
typedef TElemType SqBiTree[MAXSIZE];
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
enum PointerTag { Link, Thread }; //声明枚举,Link == 0:指针,Thread == 1:线索
typedef char TElemType;
typedef int Status;
typedef struct BiThrNode {
TElemType data;
struct BiThrNode *lchild, *rchild; //左右孩子指针
PointerTag LTag, RTag; //左右标志
}BiThrNode, *BiThrTree;
BiThrTree pre; //全局变量
//数据元素类型为BiTree的队列,用于层序遍历
typedef struct QNode {
BiTree Qdata;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
}SqQueue;
//函数列表
//*TBD1* 根据输入的先序序列创建二叉树rt
void Create_BiTree(BiTree &rt)
{
char c;
scanf("%c", &c);
if (c == '#')
rt = NULL;
else
{
rt = new BiTNode;
rt->data = c;
Create_BiTree(rt->lchild);//构造左子树
Create_BiTree(rt->rchild);//构造右子树
}
}
//*TBD2* 非递归的先序遍历(题集P42 6.37)
void preOrder(BiTree rt) {
if (rt)
{
printf("%c", rt->data);//访问根结点
preOrder(rt->lchild); //递归遍历左子树
preOrder(rt->rchild); //递归遍历右子树
}
}
//*TBD3* 层次遍历(题集P42 6.47)
//构造一个空队列Q
Status InitQueue(SqQueue *Q)
{
(*Q).front = (QueuePtr)malloc(sizeof(QNode));
if (!(*Q).front) exit(OVERFLOW);
(*Q).front->next = NULL;
(*Q).rear = (*Q).front;
return OK;
}
//探空,前提Q存在
Status QueueEmpty(SqQueue Q)
{
if (Q.front == Q.rear)
return OK;
else
return ERROR;
}
//插入元素e作为新的队尾元素,前提Q存在
Status EnQueue(SqQueue *Q, BiTree e)
{
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));//开辟新结点
if (!p) exit(OVERFLOW);
p->Qdata = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
//若队列不空,删除队头元素,用e返回其值,前提Q存在
Status DeQueue(SqQueue *Q, BiTree *e)
{
if ((*Q).front == (*Q).rear)
return ERROR;
QueuePtr p = (*Q).front->next;
*e = p->Qdata;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}
Status level(BiTree T)
{
if (!T)
return ERROR;
SqQueue Q;
InitQueue(&Q);
BiTree p;
EnQueue(&Q, T);
while (!QueueEmpty(Q))
{
DeQueue(&Q, &p);
printf("%c", p->data);
if (p->lchild)
EnQueue(&Q, p->lchild);
if (p->rchild)
EnQueue(&Q, p->rchild);
}
return OK;
}
//*TBD4* 中序遍历二叉树T,将其线索化,Thrt指向头结点
Status CreateBiTree(BiThrTree &T) { //以先序次序创建二叉树
char ch;
cin >> ch;
if (ch == '#') T = NULL;
else {
T = (BiThrNode *)malloc(sizeof(BiThrNode)); //申请空间
T->data = ch; //结点
T->LTag = Link; //初始化结点,其lchild域全部有左孩子
CreateBiTree(T->lchild); //左孩子
CreateBiTree(T->rchild); //右孩子
}
return OK;
}
void InThreading(BiThrTree p) { //联想中序遍历
if (p) {
InThreading(p->lchild); //左子树线索化
if (!p->lchild) { //寻找前驱线索
p->LTag = Thread;
p->lchild = pre;
}
if (!pre->rchild) { //寻找后继线索
pre->RTag = Thread;
pre->rchild = p;
}
pre = p; //保持pre指向p的前驱
InThreading(p->rchild); //左子树完,进行右子树线索化
}
}
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T) { //线索化算法
//中序遍历二叉树T,并将其中序线索化,Thrt指向头结点
//仿照线性表的存储结构,在二叉树的线索链表上也添加一个头结点
Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
Thrt->LTag = Link; //建立头结点
Thrt->RTag = Thread; //后继线索
Thrt->rchild = Thrt; //右指针回指
if (!T)
Thrt->lchild = Thrt; //若二叉树为空,则左指针回指
else {
Thrt->lchild = T; //头结点的左子树指向二叉树T
pre = Thrt; //pre指向刚刚访问过的结点
InThreading(T); //中序遍历进行 中序 线索化
pre->rchild = Thrt; //将最后一个线索化
pre->RTag = Thread;
Thrt->rchild = pre;
}
return OK;
}
Status PrintElement(TElemType e) { //输出函数
printf("%c",e);
return OK;
}
//*TBD5* 中序遍历线索化二叉树,Thrt的左指针指向头结点
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e)) { //第二个参数运用了函数指针,调用上一步写的输出函数
//T指向头结点,头结点的左链lchild指向根节点,参见前面的线索化算法
//中序遍历二叉树线索化T的非递归算法,对每个数据元素调用输出函数
BiThrNode *p;
p = T->lchild; //p指向根节点
while (p != T) { //空树或遍历结束后,p == T
while (p->LTag == Link)
p = p->lchild;
if (!Visit(p->data)) //访问左子树为空的结点
return ERROR;
while (p->RTag == Thread && p->rchild != T) {
p = p->rchild; //访问后继结点
Visit(p->data);
}
p = p->rchild;
}
return OK;
}
int main()
{
BiTree T1,T3;
printf("先序创建BiTree二叉树:\n");
Create_BiTree(T1);
printf("创建完成\n");
printf("先序遍历:\n");
preOrder(T1);
printf("\n");
printf("层级遍历:\n");
level(T1);
printf("\n");
BiThrNode *T2, *Thre;
printf("先序创建BiThrNode二叉树:");
CreateBiTree(T2);
printf("创建完成\n");
printf("中序遍历二叉树T2,并将其中序线索化\n");
InOrderThreading(Thre, T2);
printf("中序线索化完成\n");
printf("中序遍历并输出结果:\n");
InOrderTraverse_Thr(Thre, PrintElement);
return 0;
}
/*
ABD##E##CF##H##
ABD##E##CF##H##
*/
结果:
注意:二叉树输入必须把空的左右子树也输入上,把所有叶子节点都输入,所以本测试数据是ABD##E##CF##H##