二叉树的前序,中序线索化(C语言)

目录

一.前言

 二.线索化

三.二叉树的前序,中序线索化的思路

四.二叉树的前序,中序代码实现


一.前言

说到二叉树,大家想必觉得很熟悉,什么是二叉树?

一种由两个指针域和一个数据域构成的节点,以一种特定的顺序连接起来的存储结构。 对于二叉树这种存储结构来说,可以通过递归对其实现遍历,遍历的方式有四种,分别是前序遍历,中序遍历,后序遍历以及层序遍历,当我们以某种特定的顺序去遍历二叉树时,我们可以将遍历的结果直接输出,或者是存储在另一种数据结构中(例如:数组,栈,队列等),通过递归这种遍历的方式,一种最明显的感觉就是,仿佛一棵树以一种神奇的方式连接成了线性的结构

例如下面二叉树的前序遍历:ABDFECGHI  (遍历的路径用☆表示)  中序遍历 DBEFAHGCI (用●表示) 后序遍历 DEFBHGICA (用△表示),这样看来他们在走通过一条路。

那我们有没有什么方法将他变化成一种类似线性的结构呢? 链表?还是双向链表?   

仔细想想 ,对于二叉树来说  有n个节点 那么他必有 (n+1)个空域,对于这些被浪费的资源,我们应该合理的用起来。

 二.线索化

线索化的概念:当某节点的左指针为空时,令该指针指向按照某种方式遍历二叉树时得到该节点的前驱节点,右指针为空时,指向其直接后继节点。

如何区分节点里面指针的指向呢?

左孩子指针指向的节点是左孩子还是前驱?

右指针指向的节点是右孩子还是后继?

这里,我们采用添加线索标志位来区分这两种情况

left为0,指向左孩子,为1,指向该节点的上一个节点

right为0,指向右孩子,为1,指向该节点直接后继

节点中指向前驱结点和后继节点的指针成为线索,二叉树节点加上线索称为线索二叉树,对二叉树以某种方式遍历使其变为线索二叉树的过程称为二叉树的线索化。

三.二叉树的前序,中序线索化的思路

线索化的关键是如何确定当前节点的前驱结点和后继节点

思路:用pre 指针保存当前节点的前驱

如果当前节点的左孩子为空,就将其指向pre

如果pre的右孩子为空,就将其指向他的后继节点 也就是当前节点

四.二叉树的前序,中序代码实现

前序化代码如下

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


typedef struct Tree
{
	char ch;
	struct Tree* leftchild, * rightchild;
	int left, right;
}Tree;

Tree* pre;

/*创建一颗普通的二叉树*/
void create(Tree** T)
{
	char ch;
	scanf_s("%c", &ch);
	if (ch == '#')
	{
		(*T) = NULL;
	}
	else
	{
		(*T) = (Tree*)malloc(sizeof(Tree));
		(*T)->ch = ch;
		create(&(*T)->leftchild);
		create(&(*T)->rightchild);
	}
}

void xianxu(Tree* T)
{
	if (T)
	{
		printf("%c", T->ch);
		xianxu(T->leftchild);
		xianxu(T->rightchild);
	}
}

/*线索化前序二叉树*/
void qianxu(Tree* root)    /*线索化根为root的二叉树*/
{
	if(root)
	{
		if (root->leftchild == NULL)
		{
			root->left = 1;
			root->leftchild = pre;
		}
		else
		{
			root->left = 0;
		}

		if (root->rightchild!=NULL)
		{
			root->right = 0;
		}

		if (pre != NULL)
		{
			if (pre->rightchild == NULL)
			{
				pre->right = 1;
				pre->rightchild = root;
			}
			else
			{
				pre->right = 0;
			}
		}
		pre = root;


		if(root->left==0)
		qianxu(root->leftchild);
		
		if(root->right==0)
		qianxu(root->rightchild);
		
	}
}


void createhead(Tree** head, Tree* T)
{
	(*head) = (Tree*)malloc(sizeof(Tree));
	(*head)->left = 0;
	(*head)->right = 0;
	(*head)->rightchild = (*head);

	if (T == NULL)
	{
		(*head)->leftchild = (*head);
	}
	else
	{
		(*head)->leftchild = T;
		pre = (*head);
		qianxu(T);
		pre->rightchild = (*head);
		pre->right = 0;
		(*head)->rightchild = pre;
	}
}
/*非递归遍历中序线索二叉树*/
void bianli(Tree* head)
{
	Tree* p = head->leftchild;
	while (p != head)
	{
		while (p->left == 0)      /*从左节点开始,边遍历边输出*/
		{
			printf("%c", p->ch);
			p = p->leftchild;
		}
		printf("%c", p->ch);
		p = p->rightchild;     /*指向直接后继节点*/
	}
}








int main()
{
	//测试案例:ABD#G###CE##F##
	Tree* t;
	Tree* head;
	printf("请输入节点数据('#'为空):\n");
	create(&t);
	printf("先序遍历如下:\n");
	xianxu(t);
	printf("\n前序线索化非递归遍历如下:\n");
	createhead(&head, t);
	bianli(head);
	return 0;
}

中序化类似

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


typedef struct Tree
{
	char ch;
	struct Tree* leftchild, * rightchild;
	int left, right;
}Tree;

Tree* pre;

/*创建一颗普通的二叉树*/
void create(Tree** T)
{
	char ch;
	scanf_s("%c", &ch);
	if (ch == '#')
	{
		(*T) = NULL;
	}
	else
	{
		(*T) = (Tree*)malloc(sizeof(Tree));
		(*T)->ch = ch;
		create(&(*T)->leftchild);
		create(&(*T)->rightchild);
	}
}

void xianxu(Tree* T)
{
	if (T)
	{
		printf("%c", T->ch);
		xianxu(T->leftchild);
		xianxu(T->rightchild);
	}
}

/*线索化中序二叉树*/
void zhongxu(Tree* root)    /*线索化根为root的二叉树*/
{
	if (root)
	{
		zhongxu(root->leftchild);
		if (root->leftchild == NULL)
		{
			root->left = 1;
			root->leftchild = pre;
		}
		else
		{
			root->left = 0;
		}
		if (pre != NULL && pre->rightchild == NULL)
		{
			pre->right = 1;
			pre->rightchild = root;
		}
		pre = root;
		zhongxu(root->rightchild);
	}
}


void createhead(Tree** head, Tree* T)
{
	(*head) = (Tree*)malloc(sizeof(Tree));
	(*head)->left = 0;
	(*head)->right = 1;
	(*head)->rightchild = (*head);

	if (T == NULL)
	{
		(*head)->leftchild = (*head);
	}
	else
	{
		(*head)->leftchild = T;
		zhongxu(T);
		pre->rightchild = (*head);
		pre->right = 1;
		(*head)->rightchild = pre;
	}
}
/*非递归遍历中序线索二叉树*/
void bianli(Tree* head)
{
	Tree* p = head->leftchild;
	while (p != head)
	{
		/*找到最左的节点*/
		while (p->left == 0)
			p = p->leftchild;

		/*输出最左侧节点的值*/
		printf("%c  ", p->ch);
		/*输出当前节点的根节点*/
		while (p->right == 1 && p->rightchild != head)
		{
			p = p->rightchild;
			printf("%c  ", p->ch);
		}
		/*向右节点走*/
		p = p->rightchild;
	}
}


int main()
{
	//测试案例:ABD#G###CE##F##
	Tree* t;
	Tree* head;
	printf("请输入节点数据('#'为空):\n");
	create(&t);
	printf("先序遍历如下:\n");
	xianxu(t);
	printf("\n中序线索化非递归遍历如下:\n");
	createhead(&head, t);
	bianli(head);
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值