二叉树遍历及线索化算法

二叉树遍历及线索化算法

部分参考严蔚敏数据结构一书
实现:
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##

猜你喜欢

转载自blog.csdn.net/weixin_46020391/article/details/110588993