树(三)——二叉树遍历的应用

目录

一、建立二叉链表存储的二叉树   

补充:

二、统计二叉树的结点数

三、统计二叉树的叶子结点

四、输出叶子结点

五、求二叉树的高度

六、求结点的双亲

七、二叉树相似性的判定

八、按照树形形状打印二叉树

九、算法实现综合应用

 以此图为例:

 算法实现:

运行结果:


一、建立二叉链表存储的二叉树   

二叉树结点的结构:

typedef struct Node
{
    TypeData data;
    struct Node*LChild;
    struct Node*RChild;
}BiTreeNode,*BiTree;

                   

采用扩展的先序遍历序列建立二叉链表

存储时为了区分空子树与非空子树,自定义个符号用于区分。

                               

函数中的形参:指向结点的指针(*root),用于接收实参,(指向根结点的指针)root 的地址。                                                          

                                                          

如果输入的值 A 非空则为(*root)申请一个结点空间,用于存放输入的值,

按照先序遍历的顺序该 A 结点的左子树 B 接收下一个输入的值,

如果左子树 B 为空(自定义值)跳转到上一层,开始遍历其右子树,

其左子树B非空时: 遍历左子树根结点的左子树 C此时采用递归调用),

……

结点C调用结束后,会跳转到上一层B,继续遍历右子树D。

补充:

递归实现,有一个缺点是,

因为为了区分空树与非空树,我们采用自定义符号,这里采用 ^,

而在递归一层层调用时,需要注意右子树为^时会回溯到上一层,而如果输入的值与^数目不符合时,也就是不满足回到根结点的左子树时,造成根结点的右子树没有进行存储,此二叉树会继续让你输入值。

建立的二链表存储结束的条件是,根结点的右子树存储结束。


二、统计二叉树的结点数

                       

结点数=根结点+左子树结点数+右子树结点

 先序遍历,先遍历左子树,(采用递归的方法)直到左子树为0;然后遍历右子树,

最后加上根结点。

                                            

 根结点a

遍历其左子树b(采用递归调用),

如果 b 的左子树为空,跳转到上一层,递归遍历右子树

如果右子树也为空 则 b 的结点数只有一个根结点,结点数为1,然后跳转到上一层,

然后递归遍历右子树 f 。


三、统计二叉树的叶子结点

int number0(BiTree root)
{
    if(root==NULL)     //判断树是否为空,空树是无结点,也可以是子树  
      return 0;
    if((root->LChild==NULL)&&(root->RChild==NULL))   //左右子树都为空时满足叶子结点,返回1
      return 1;
    else
       return number0(root->LChild) + number0(root->RChild);  
       //如果根结点有左子树或右子树,或同时有,先继续递归调用左子树,结束后返回到上一层,调用右子树 
}

             

                                      

注意:叶子结点数=左子树的叶子结点数+右结点的叶子结点数,因为是递归调用,

观察图

b 的左子树结点 C非空:

                             判断结点c的左右子树,左右子树都为空,返回 1,

然后判读b的右子树结点 d 非空:

                            判断b的右子树 d 的叶子结点只有 e返回1,此时b的左右子树调用完后,

 返回到上一层b,此时b的叶子结点为(c+d)=2 ,此时a的左子树b判断完毕

 继续调用a的右子树 f

 同理,f的叶子结点数为1a的左右子树调用完毕,

 返回到上一层 a此时a的叶子结点数为(b+f)=3

如果a为空:则为空树,叶子结点为0

否则: 判断 a 的左子树 b和右子树 f 是否为空。

如果:左右子树都存在或只存在一个:先递归调用 左子树 b 继续判断,调用结束,然后调用其右子树 f。

否则:返回1,只有一个叶子结点 a。

调用左子树 b 时:如果 b 为空返回0,

否则:判段 b的左右子树                      


四、输出叶子结点

输出叶子结点时,需要遍历树,每一个结点需要判断是不是叶子结点

先序遍历应用:

void InOrder(BiTree root)
{
	if (root)
	{
		if (root->LChild == NULL && root->RChild)  //叶子结点的判断条件
			printf("%c ", root->data);
		InOrder(root->LChild);                    //递归遍历左子树
		InOrder(root->RChild);                     //递归遍历右子树
	}
}

五、求二叉树的高度

求二叉树的高度,需要遍历左右子树,判断左右子树哪颗树更高,则需要知道左右子树的深度的层次,定义一个 h 表示树的层次。

int Deepth(BiTree root)
{
    int h1,h2;
    if(root==NULL)
      return 0;
    h1=Deepth(root->LChild);
    h2=Deepth(root->RChild);
    return (h1>h2?h1:h2)+1;      //判读h1,h2的大小,输出大的一个高度再加上根结点
}

六、求结点的双亲

求一个结点A的的双亲,函数的参数就需要接收这个结点,便于查找双亲。

查找双亲结点B的方法:

     递归判断左子树中是否存在一个结点B的左孩子或右孩子等于条件结点A,如果是,直接返回结点 B。否则,同理,进入右子树判断是否存在。

先从左子树中查找,查找结束判断,符合条件在从右子树查找。

BiTree relative(BiTree root,BiTree Node)
{
    BiTree* p;               //指向双亲结点的指针,方便判断是否遍历右子树
    if(root==NULL)           //如果树为空返回NULL
      return NULL;
    if((root->LChild==Node)||(root->RChild==Node))  //如果存在满足条件,返回双亲结点
      retrun root;                 // 没有找到时,继续递归左子树。
    p=relative(root->LChild);
    if(p!=NULL)               
      return *p;                //如果左子树查找到结点,返回双新结点,否则,递归遍历右子树
    else
      return relative(root->RChild);
}
   

七、二叉树相似性的判定

明确:二叉树相似是结构相似,不是二叉树的值都相等

二叉树相似的判定过程(两个二叉树为例)中出现的情况有三种

1、两个二叉树都为空树

2、一个二叉树为空,另一个二叉树非空

3、两个二叉树都不为空,都不为空时,分别需要判断两树的左子树,和右子树结构是否相似。

如何判断结构是否相似呢?或者是如何知道两树的左子树或者右子树相似呢?

   判断两左子树时需要,共同比较两左子数是否都为空,都为空时,结构相似,因为是一起递归遍历。

int similar(BiTree root1,BiTree root2)
{
   int like1,like2;              //用于判断左右子树是否相似
   if(root1==NULL&&root2==NULL)       //两个二叉树都为空
     return 1;                    //相似返回1
   if(root1==NULL||root2==NULL)     
     return 0;
   like1=similar(root1->LChild,root2->LChild);  //递归判断两树的左子树是否相似
   like2=similar(root1->RChild,root2->RChild);  
   return (like1&&like2);          //根据两左子树和右子树的结果判断两树是否相似
}

八、按照树形形状打印二叉树

展示的效果是横向的二叉树,

按照右子树,然后根结点,然后左子树的方式打印二叉树。

如何确定结点的横向位置?

需要根据结点的层次h,然后在结点前打印h-1个空,用于展示位置的效果

//按照树的形状打印树   打印顺序是先右子树,根结点,左子树
void Print(BiTree root,int h)  //通过结点的层数判断打印的位置
{
	if (root == NULL)
		return;
	Print(root->RChild, h + 1);    //先打印右子树
	for (int i = 1; i <= h; i++)   //结点的位置,前面的空位数为上一层的层数
		printf(" ");
	printf("%c\n", root->data);
	Print(root->LChild, h + 1);     //打印左子树;
}

九、算法实现综合应用

 以此图为例:

                           

 算法实现:

#include<stdio.h>
#include<stdlib.h>
// 建立二叉树的结构
typedef struct Node
{
	char data;
	struct Node* LChild;
	struct Node* RChild;
}BiTreeNode ,*BiTree;

//建二叉链表存储的二叉树
void Establish(BiTree*root)
{
	char demo;
	demo = getchar();
	if (demo == '^')
		*root = NULL;
		else
		{
			*root = (BiTree)malloc(sizeof(BiTreeNode));
			(*root)->data = demo;
			Establish(&((*root)->LChild));
			Establish(&((*root)->RChild));
		}
} 

// 先序遍历求二叉树的结点数
int Number(BiTree root)
{
	if (root == NULL)
		return 0;
	else
		return Number(root->LChild)+Number(root->RChild)+1;
}	 

// 先序遍历求二叉树的叶子结点数
int Number0(BiTree root)
{
	if (root == NULL)   //如果是空树返回0
		return 0;
	if ((root->LChild == NULL) && (root->RChild == NULL))  //该结点为空
		return 1;
	else                                                   //该结点不为空,继续调用函数遍历
	return Number0(root->LChild) + Number0(root->RChild);
}

//先序遍历输出二叉树的叶子结点
void InOrder(BiTree root)
{ 
	if (root)
	{
	   if (root->LChild == NULL && root->RChild==NULL)
		   printf("%c ", root->data);
	   InOrder(root->LChild);
	   InOrder(root->RChild);
	}
}

 //先序遍历求二叉树的深度
int Deepth(BiTree root)
{
	if (root == NULL)
		return 0;
	else
	{
	int h1 = Deepth(root->LChild);
	int h2 = Deepth(root->RChild);
	return (h1 > h2 ? h1 : h2 )+ 1;
	}
}

//求结点的双亲
BiTree relative(BiTree root,BiTree TreeNode)
{
	BiTree *p=NULL;
	if (root == NULL)
		return NULL;
	if ((root->LChild == TreeNode) || (root->RChild == TreeNode))
		return root;                                          // 结点的左子树与TreeNode不等
	*p = relative(root->LChild, TreeNode);          // 继续遍历左子树,
	if (p != NULL)                                // 左子树遍历结束没有找到,在右子树中查找
		return  *p;
	else
		return relative(root->RChild, TreeNode);
}

// 求结点的相似性   是判断两个树的结构是否相同,而不是相等
int simmilar(BiTree root, BiTree root1)
{
	int like1, like2;
	if (root == NULL && root1 == NULL)  //两个都为空树,相似返回1
		return 1;
	if (root == NULL || root1 == NULL)   // 其中一个为空树,返回0
		return 0;
	like1 = simmilar(root->LChild, root1->LChild);  // 继续遍历左子树
	like2 = simmilar(root->RChild, root1->RChild);
	return (like1 && like2);
}

//按照树的形状打印树   打印顺序是先右子树,根结点,左子树
void Print(BiTree root,int h)  //通过结点的层数判断打印的位置
{
	if (root == NULL)
		return;
	Print(root->RChild, h + 1);    //先打印右子树
	for (int i = 1; i <= h; i++)   //结点的位置,前面的空位数为上一层的层数
		printf(" ");
	printf("%c\n", root->data);
	Print(root->LChild, h + 1);     //打印左子树;
}
main()
{
	BiTree root;
	Establish(&root);
	printf("-----------统计二叉树结点数----------\n");
	printf("%d\n",Number(root));
	printf("-----------统计二叉树叶子结点数----------\n");
	printf("%d\n", Number0(root));
	printf("------------输出叶子结点--------------\n");
	InOrder(root);
	printf("\n");
	printf("-------------统计二叉树的高度--------------\n");
	int h=Deepth(root);
	printf("%d\n", h);
	printf("-----------打印二叉树------------\n");
	Print(root, h);
 }

运行结果:

                               

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值