以孩子兄弟链作为树的存储结构设计一个求树t的高度的递归算法

一、左孩子右兄弟存储结构思想

1.1左孩子右兄弟存储结构

A
B
C
D
E
F
G
H

如上图所示是一个树的结构,如何将这个树使用左孩子右兄弟的存储方式将其保存到内存中呢?

其实,将这棵树分为两部分左边只连接孩子,并且只能是长子右边只连兄弟,但要注意在树中只有亲兄弟才算兄弟,如E与F是兄弟,而F与G不是兄弟。只要遵循这一原则,那么就可以以此将上面的树以左孩子右兄弟的方式存储起来。实际上,这种存储方式就是将该树转换成二叉树。由于二叉树结构简单且固定,因此转换成二叉树后续使用递归函数。

左孩子右兄弟存储可表示如下图所示

A
NULL
B
C
NULL
D
NULL
E
F
NULL
NULL
G
NULL
NULL
H
NULL
NULL

如上图所示清晰的展示了使用该结构存储后在内存中的逻辑结构,题目中的树已经被转化成二叉树的结构,方便我们进行下一步操作。

思考

这一步操作结束以后大家是否会产生这样的疑问,是不是只能是左孩子右兄弟,难道左兄弟右孩子不可以吗?

关于这个问题在构建递归函数时就会有答案了

二、递归函数模块架构

2.1五大常用算法——分治算法

分治算法顾名思义就是分而治之,将一个大问题分解成多个小问题,再将各个小问题分解,直到不可再分。而递归实际上也是以这种分治的思想来解决问题。

在上一步操作中,我们已经将该树转变成二叉树类型的结构。在二叉树中不管这个二叉树有多高只需要关注三个东西根节点、左子树和右子树。为什么只需要关注这个东西呢?其实我们仔细观察上面的逻辑图就很容易发现不管多复杂的二叉树都是有这三个基本的东西堆积而成的。

如下图:

A
NULL
B

取上述图中的一部分来看,这就是一个最简单的二叉树只有上述所说的三个结构。通过分治算法的思想我们可以看出B还可以在往下分成根节点、左子树和右子树,直到左子树和右子树都为NULL,说明已经达到不可再分。这就是编写递归函数模块的思想。

三、多文件编写程序

有了上述的分治算法的思想后,就可以多文件编写程序。

头文件(TreeHeigh.h)

#pragma once

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

typedef char ElemType;

typedef struct TreeNode
{
	ElemType data;
	struct TreeNode* kid;
	struct TreeNode* bro;
}TN;


int TreeHeigh(TN* t);//求出树的高度

void DeleTree(TN* root);//释放malloc函数开辟的空间

子函数模块(TreeHeigh.c)

#include "TreeHeigh.h"

int TreeHeigh(TN* t)
{
	TN* p = NULL;
	int h = 0;
	int maxh = 0;

	if (t == NULL)//判断是否为空树
	{
		return 0;
	}
	else
	{
		p = t->kid;			//p指向第一个孩子结点
		while (p != NULL)	//遍历t的所有子树
		{
			h = TreeHeigh(p);	//通过递归求出子树高度
			if (maxh < h)
			{
				maxh = h;
			}
			p = p->bro;			//继续处理其他子树
		}
		return (maxh + 1);
	}
}

void DeleTree(TN* root)
{
	if (root)
	{
		DeleTree(root->kid);//先往左子树一直寻找

		DeleTree(root->bro);//再往右子树一直寻找

		free(root); //找不到了free返回上一级

		root = NULL;
	}
}

主函数模块(Text.c)

#include "TreeHeight.h"

int main()
{
	//以下是为了直观的看到该结构是怎样连接,因此是分别开辟空间。
	//也可以自行编写函数调用,此处不再展示
	TN* A = (TN*)malloc(sizeof(TN));
	A->data = 'A';
	A->kid = NULL;
	A->bro = NULL;

	TN* B = (TN*)malloc(sizeof(TN));
	B->data = 'B';
	B->kid = NULL;
	B->bro = NULL;

	TN* C = (TN*)malloc(sizeof(TN));
	C->data = 'C';
	C->kid = NULL;
	C->bro = NULL;

	TN* D = (TN*)malloc(sizeof(TN));
	D->data = 'D';
	D->kid = NULL;
	D->bro = NULL;

	TN* E = (TN*)malloc(sizeof(TN));
	E->data = 'E';
	E->kid = NULL;
	E->bro = NULL;

	TN* F = (TN*)malloc(sizeof(TN));
	F->data = 'F';
	F->kid = NULL;
	F->bro = NULL;

	TN* G = (TN*)malloc(sizeof(TN));
	G->data = 'G';
	G->kid = NULL;
	G->bro = NULL;

	TN* H = (TN*)malloc(sizeof(TN));
	H->data = 'H';
	H->kid = NULL;
	H->bro = NULL;

	//将树之间按照左兄弟右孩子规则连接
	A->kid = B;
	B->kid = D;
	B->bro = C;
	D->bro = E;
	E->kid = H;
	E->bro = F;
	C->kid = G;

	int height = TreeHeigh(A);
	printf("这棵树的深度为:%d", height);

	DeleTree(A);

	return 0;

 }
}

运行程序后,结果如下图所示
运行结果图
在本段代码中,最为核心的就是递归的调用。如果难以理解递归,也可以将递归展开图画出。在上述中留下了一个问题,即左孩子右兄弟,能否换成左兄弟右孩子。理论上是不可以,我们在使用递归函数时采用先根遍历,也就是说要左子树遍历完之后才去遍历右子树,如果交换位置逻辑上就会出错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值