中序线索二叉树的建立(非递归方式)与遍历【C语言实现】

案例使用的二叉树如下图所示:

 

#include<stdio.h>
#include<stdlib.h>

// 函数状态代码
#define TRUE 1 // 逻辑1
#define FALSE 0 // 逻辑0
#define OK 1 // 程序运行无误
#define ERROR 0 // 程序运行有误
#define INFEASIBLE -1
#define OVERFLOW -2 // 结果溢出
typedef int Status; // 函数状态类型:int
typedef int boolean; // 布尔类型:int

//-----二叉树结点数据元素-----
typedef int TreeElem; // int型 

//-----线索二叉树存储结构-----
typedef struct ThreadNode
{
	TreeElem data; // 数据域
	struct ThreadNode *lchild, *rchild; // 左右线索指针
	boolean ltag, rtag; // 左右标志
}ThreadNode, *ThreadTree;

//-----辅助数据结构数据元素类型-----
typedef ThreadNode* AElem;

//-----辅助栈存储结构-----
typedef struct SNode
{
	AElem data; // 数据域
	struct SNode *next; // 指针域
}SNode, *linkStack;

//-----辅助栈相关操作-----
Status InitStack(linkStack *S)
{// 初始化栈S
	SNode *s; // 工作指针
	s = (SNode*)malloc(sizeof(SNode)); // 新建表头结点
	s->data = NULL; // 数据域赋初值
	s->next = NULL; // 指针域赋初值
	*S = s; // 栈指针指向此新建结点
	return OK;
}// InitStack()

boolean StackIsEmpty(linkStack S)
{// 判断栈S是否为空
	if(S->next==NULL)
		return TRUE;
	return FALSE;
}// StackIsEmpty()

Status DisplayStack(linkStack S)
{// 可视化输出链栈S
 /*
	使用遍历指针p依次输出从栈顶到栈底的所有元素	
 */
	SNode *p=S->next; // 遍历指针
	while(p!=NULL) // p非空时
	{
		visit(p->data); // 访问数据域
		printf("\n");
		p = p->next; // 继续遍历
	}// while
	return OK;
}// DisplayStack()

Status GetTop(linkStack S, AElem *x)
{// 获取栈顶元素并使用x返回
	if(S->next==NULL) // 栈为空
		return ERROR;
	else
		*x = S->next->data;
	return OK;
}// GetTop()

Status Push(linkStack S, AElem x)
{// 将数据元素x入栈
 /*
	基本思想:新建结点按头插法插入链栈中
 */
	SNode *s; // 工作指针
	s = (SNode*)malloc(sizeof(SNode)); // 新建结点
	s->data = x; // 数据域赋值
	s->next = S->next; // 完善指针域
	S->next = s;
	return OK;
}// Push()

Status Pop(linkStack S, AElem *x)
{// 弹栈并使用x接收弹出结点的数据域值
 /*
	基本思想:首先接收栈顶元素值并判断是否可弹栈,若可弹栈,删除栈顶结点。
 */
	SNode *s=S->next; // 工作指针
	if(!(GetTop(S, x))) // 无法获取栈顶元素说明栈为空,此时无法弹栈
		return ERROR;
	S->next = s->next; // 逻辑删除
	free(s); // 物理删除
	return OK;
}// Pop()

//-----线索二叉树相关操作-----
Status visit(ThreadNode *s)
{// 输出所指向的二叉结点的数据域
	if(s==NULL)
		return ERROR;
	printf("%d ", s->data);
	return OK;
}// visit()

Status Example(ThreadTree *T)
{// 将案例加载到线索二叉树T
	ThreadNode *s, *p, *q; // 工作指针
	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 1;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	*T = s;
	p = s;

	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 2;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	p->lchild = s;

	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 3;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	p->rchild = s;

	q = p->rchild;
	p = p->lchild;

	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 4;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	p->lchild = s;
	
	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 5;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	p->rchild = s;

	q = p->rchild;

	s = (ThreadNode*)malloc(sizeof(ThreadNode)); // 新建结点
	s->data = 6;
	s->lchild = NULL;
	s->ltag = FALSE;
	s->rchild = NULL;
	s->rtag = FALSE;

	q->lchild = s;

	return OK;
}// Example()

Status CreateInThread(ThreadTree T)
{// 中序线索化二叉树T
 /* 基本思想:使用指针p遍历二叉树所有结点。指针pre指示上一个输出的结点。在指针p非空或栈非空时进行如下循环:
	若指针p非空,将此结点入栈并向左下进发;若指针p为空,弹栈,若此结点前驱为NULL,将其前驱修改为pre,p向右下
	进发,同时,若pre的后继为NULL,将后继修改到此结点。
*/
	ThreadNode *p=T; // 二叉结点遍历指针
	AElem x;
	ThreadNode *pre=NULL; // 指示上一个输出的结点
	linkStack S; // 辅助栈

	InitStack(&S); // 初始化栈
	while(p!=NULL||(!(StackIsEmpty(S)))) // p非空或栈非空
	{
		if(p!=NULL) // p指向新结点
		{
			Push(S, p); // 新结点入栈
			p = p->lchild; // 向左下进发
		}// if
		else // p为空
		{
			Pop(S, &x); // 获取栈顶元素
			if(x->lchild==NULL) // 弹栈结点左孩子为空
			{
				x->lchild = pre;
				x->ltag = TRUE;
			}// if
			if(pre!=NULL&&pre->rchild==NULL) // pre右孩子为空
			{
				pre->rchild = x;
				pre->rtag = TRUE;
			}// if
			pre = x;
			p = x->rchild;
		}// else
	}// while

	return OK;
}// CreateInThread()

ThreadNode* FirstNode(ThreadTree T)
{// 返回以p所指结点为根结点的二叉树的线索遍历序列第一个结点
 /*
	基本思想:在T非空的情况下,一直向左下前进直到某个左标志为TRUE的结点。
	*/
	ThreadNode *p=T; // 遍历指针
	if(T==NULL) // 树为空
		return NULL;
	while(p->ltag==FALSE)
	{
		p = p->lchild;
	}// while
	return p;
}// FirstNode()

ThreadNode* NextNode(ThreadNode *s)
{// 返回指针s所指结点在遍历序列的下一个结点
 /*
	基本思想:若s为空,返回NULL。若s右标志为TRUE,s的右孩子即为下一个结点;若s右标志为FALSE,下一个结点
	为以s右孩子为根二叉树遍历序列的首个结点。
	*/
	if(s==NULL) // 非法输入
		return NULL;
	if(s->rtag==TRUE) // s右标志为TRUE
		return s->rchild;
	else
		return FirstNode(s->rchild);
}// NextNode()

Status InOrder_Thread(ThreadTree T)
{// 中序遍历线索化二叉树
 /*
	基本思想:使用一指针p遍历二叉树所有结点。依照线索,从第一个结点遍历到最后一个结点。
	*/
	ThreadNode *p=FirstNode(T); // 遍历指针
	while(p!=NULL) // 遍历线索化二叉树
	{
		visit(p); // 访问结点
		p = NextNode(p); // 继续遍历
	}// while
	printf("\n");
	return OK;
}// InOrder_Thread()

// 主函数
void main()
{
	ThreadTree T;
	ThreadNode *s;
	if(Example(&T))
		printf("线索二叉树已初始化!\n");
	if(CreateInThread(T))
		printf("二叉树已线索化!\n");
	InOrder_Thread(T);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值