线索二叉树的创建、中序线索二叉树的前驱和后继、先序线索二叉树的前驱和后继、后序线索二叉树的前驱和后继的实现

1 线索二叉树的创建

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

//*************************************************************************************************************
typedef char DataType;
typedef struct BiTNode {
	DataType data;
	int LTag;
	int RTag;
	struct BiTNode *LChild;
	struct BiTNode *RChild;
	struct BiTNode *parent;//用于记录其父节点
}BiTNode, *BiTree;

void Visit(DataType data)
{
	printf("%c, ", data);
}

//创建时不顺带设置其parent
void CreateBiTree(BiTree *root)
{
	char ch;
	ch = getchar();
	if (ch == '.')   *root = NULL;
	else {
		*root = (BiTNode *)malloc(sizeof(BiTNode));
		(*root)->data = ch;
		(*root)->LTag = 0;
		(*root)->RTag = 0;
		(*root)->parent = nullptr;
		CreateBiTree(&((*root)->LChild) );
		CreateBiTree(&((*root)->RChild));
	}
}

//创建时顺便设置其parent
void CreateBiTree2(BiTree *root, BiTNode *parent)
{
	char ch = getchar();
	if (ch == '.') *root = NULL;
	else {
		*root = (BiTNode *)malloc(sizeof(BiTNode));
		(*root)->data = ch;
		(*root)->LTag = 0;
		(*root)->RTag = 0;
		(*root)->parent = parent;
		CreateBiTree2(&((*root)->LChild), *root);
		CreateBiTree2(&((*root)->RChild), *root);
	}
}

2 【将一棵树中序线索化、求中序遍历的第一个节点、中序遍历的前驱、中序遍历的后继、中序线索二叉树的遍历】

BiTNode *pre = NULL;
//将一棵树中序线索化
void InThread(BiTree root)
{
	if (root == NULL) return;

	InThread(root->LChild);
	if (root->LChild == NULL) {
		root->LTag = 1;
		root->LChild = pre;
	}
	if (pre != NULL && pre->RChild == NULL) {
		pre->RTag = 1;
		pre->RChild = root;
	}
	pre = root;
	InThread(root->RChild);
}

//求中序遍历的第一个结点:LDR左子树的最左边
BiTNode * InFirst(BiTree root)
{
	if (root == NULL)  return NULL;
	BiTNode *p = root;
	while (p->LTag == 0) {
		p = p->LChild;
	}
	return p;
}

//求中序遍历的前驱:左子树的最右边
BiTNode * InPre(BiTree root)
{
	BiTNode *pre, *p;
	if (root->LTag == 1)
		pre = root->LChild;
	else {
		for (p = root->LChild, pre = p; p->RTag == 0; ) {
			p = p->RChild;
			pre = p;
		}
	}
	return pre;
}

//求中序遍历的后继:LDR 右子树的最左边
BiTNode * InNext(BiTree root)
{
	BiTNode * next, *p;
	if (root->RTag == 1) next = root->RChild;
	else {
		//root可能是最后一个结点,其root->RChild为空,即p为NULL,p->LTag报错,
		//正解应该是将中序线索化的最后一个节点的R-Tag置为1或者在此处加上对p非空的判断
		for (p = root->RChild, next = p; p&& p->LTag == 0;) {
			p = p->LChild;
			next = p;
		}
	}
	return next;
}

//遍历中序线索二叉树
void TranverseInThread(BiTree root)
{
	BiTNode *p = InFirst(root);
	while (p) {
		Visit(p->data);
		p = InNext(p);
	}
}

3 【将一棵树先序线索化、求先序遍历的第一个节点、先序遍历的前驱、先序遍历的后继、中序线索二叉树的遍历】

//将一棵树先序线索化
void PreThread(BiTree root, BiTNode * &pre)
{
	if (root == NULL) return;

	BiTNode * lchildTemp = root->LChild;
	if (root->LChild == NULL) {
		root->LTag = 1;
		root->LChild = pre;
	}
	if (pre != NULL && pre->RChild == NULL) {
		pre->RTag = 1;
		pre->RChild = root;
	}
	pre = root;
	PreThread(lchildTemp, pre);//因为root->Lchild可能已经被修改成其前驱了
	PreThread(root->RChild,pre);
}

//建立一棵先序线索化二叉树
void CreatePreThread(BiTree root)
{
	BiTNode * pre = NULL;
	if (root != NULL) {
		PreThread(root, pre);
		pre->RChild = NULL;
		pre->RTag = 1;
	}
}

//求先序遍历的第一个结点:DLR 有根则为根结点
BiTNode* PreFirst(BiTree root)
{
	if (root == NULL) return NULL;
	else
		return root;
}

//重新填链表的parent值
void FillParent(BiTree root)
{
	if (root != NULL)
	{
		if (root->LChild)
			root->LChild->parent = root;
		if(root->RChild)
			root->RChild->parent = root;
		FillParent(root->LChild);
		FillParent(root->RChild);
	}
}

//求先序遍历的前驱
//1.如果是根结点,其前驱是NULL: pre
//2.如果p是某个结点M的左孩子,不管这棵左子树有没有左孩子,则其前驱:pre = parent(p) = M
//(如果这棵左子树没有左孩子,也可以通过root->LChild直接获得其前驱)
//3.如果p是某个结点M的右孩子,且M没有左子树,则前驱 = parent(p) = M
//4.如果p是某个结点M的右孩子,且M有左子树,则前驱:pre = M左子树的最右下
//总结:之所以不以root->LTag来分类,是因为如果root->LTag == 0, 即有左孩子,其前驱可能是父节点也可能是4中的左子树最右下
BiTNode * PrePre(BiTree root)
{
	if (!root) return NULL;
	if (root->parent == NULL)
		return NULL;
	BiTNode * parent = root->parent;
	if (parent->LChild == root)
		return parent;
	if (parent->RChild == root && parent->LTag == 1)
		return parent;
	if (parent->RChild == root && parent->LTag == 0) {
		BiTNode *leftRightMost = parent->LChild;
		while (leftRightMost->RTag == 0)
			leftRightMost = leftRightMost->RChild;
		return leftRightMost;
	}
}

//求先序遍历的后继DLR
//1.如果有左子树,那么左孩子就是其后继
//2. 否则  如果有右子树,那么右孩子就是其后继;否则利用root->RTag =1可以直接找到后继
//总结:如果有左子树,那么左孩子root->LChild就是后继;不然root->LChild就是其后继
BiTNode * PreNext(BiTree root)
{
	if (root == NULL) return NULL;
	if (root->LTag == 0) return root->LChild;
	else
		return root->RChild;
}

//遍历先序线索二叉树
void TranversePreThread(BiTree root)
{
	BiTNode *p = PreFirst(root);
	while (p) {
		printf("%c,", p->data);
		p = PreNext(p);
	}
}

4 【将一棵树先序线索化、求先序遍历的第一个节点、先序遍历的前驱、先序遍历的后继、中序线索二叉树的遍历】

//将一棵树后序线索化
void PostThread(BiTree root , BiTNode *&pre)
{
	if (root == NULL) return;

	PostThread(root->LChild, pre);
	PostThread(root->RChild,pre);
	if (root->LChild == NULL) {
		root->LTag = 1;
		root->LChild = pre;
	}
	if (pre != NULL && pre->RChild == NULL) {
		pre->RTag = 1;
		pre->RChild = root;
	}
	pre = root;
}

//创建一棵后序线索二叉树
void CreatePostThread(BiTree root)
{
	BiTNode *pre = NULL;
	if (root != NULL) {
		PostThread(root, pre);
		//pre->RChild = NULL;在后序线索二叉树不能将最后一个结点的RChild置为NULL,不然可能会把根结点的右子树变成NULL
		//pre->RTag = 1;也不能改变标记,不然就是说pre->RChild是其后继
	}
}

//求一个子树的最左下结点
BiTNode* LeftDownMost(BiTree root)
{
	if (root == NULL) return NULL;
	BiTNode * p = root;
	while (p->LTag == 0)
		p = p->LChild;
	return p;
}

//求后序遍历的第一个结点
BiTNode *PostFirst(BiTree root)
{
	if (root == NULL) return NULL;
	if (root->LTag == 0)
		return PostFirst(root->LChild) ;
	else if (root->RTag == 0)
		return PostFirst(root->RChild);
	else
		return root;
}

//求后序遍历的前驱
//1.如果右子树不为空,则前驱为右孩子
//2.如果右子树为空,但是左子树不为空,则为左孩子
//3.如果左右子树均为空,则其前驱不一定是NULL(即当前结点为根结点的情况),应该利用root->Ltag == 1来求得
//总结:上述可总结为:如果右子树不为空,则前驱是root->RChild,否则为root->LChild;
//上述思路也可逆过来:先判断root->Ltag == 1,则直接获得前驱;否则说明有左子树,然后根据是否有右子树划分为两类情况
BiTNode * PostPre(BiTree root)
{
	if (root == NULL) return NULL;
	if (root->RTag == 0)
		return root->RChild;
	else 
		return root->LChild;
}

//求后序遍历的后继
//1.如果是根结点,那么其后继为NULL
//2.如果当前结点是其父节点的右孩子结点,则其后继为其父节点
//3.如果当前结点是其父节点的左孩子结点,并且父节点的右子树为空,则其后继为其父节点
//4.如果当前结点是其父节点的左孩子结点,并且父节点的右子树不为空,则其后继为右子树的最左下结点
BiTNode *PostNext(BiTree root)
{
	if (root == NULL) return NULL;
	if (root->parent == NULL)
		return NULL;
	BiTNode *parent = root->parent;
	if (parent->RChild == root)
		return parent;
	if (parent->LChild == root && parent->RTag == 1)
		return parent;
	if (parent->LChild == root && parent->RTag == 0)
		return LeftDownMost(parent->RChild);
}

//遍历后序线索二叉树
void TranversePostThread(BiTree root)
{
	BiTNode * p = PostFirst(root);
	while (p) {
		printf("%c,", p->data);
		p = PostNext(p);
	}
}

5 测试主程序

void PrintPreOrder(BiTree root)
{
	if (root != NULL) {
		printf("%c,", root->data);
		PrintPreOrder(root->LChild);
		PrintPreOrder(root->RChild);
	}
}

//*******************************************************************************************************************

int main()
{
	BiTree root, nodePre; // AB.C..DE..F...
	CreateBiTree(&root);
	InThread(root);
	pre->RTag = 1;//将中序线索化的最后一个节点的R-Tag置为1, 否则其被认为有右孩子,而右孩子实际为空
	TranverseInThread(root); 
	nodePre = InPre(root->LChild->RChild);
	if(nodePre !=NULL)
		printf("The pre node of C is :%c\n", nodePre->data);
	else
		printf("\nThe node is the first one, no pre node!\n");

	getchar();
	BiTree root2;
	CreateBiTree(&root2);// AB.C..DE..F..
	FillParent(root2);
	PrintPreOrder(root2);

	CreatePreThread(root2);
	printf("\nThe root2 PreThread tree is :\n");
	TranversePreThread(root2);
	nodePre = PrePre(root2);//->RChild->LChild
	if (nodePre != NULL)
		printf("\nThe pre node of D is :%c\n", nodePre->data);
	else
		printf("\nThe node is the first one, no pre node!\n");

	getchar();
	BiTree root3;
	CreateBiTree2(&root3,NULL);
	//PrintPreOrder(root3);
	CreatePostThread(root3);
	TranversePostThread(root3);
	nodePre = PostPre(root3);
	if (nodePre != NULL)
		printf("\nThe pre node of A  is :%c\n", nodePre->data);
	else
		printf("\nThe node is the first one, no pre node!\n");
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值