彻底搞懂广义表-求其深度的代码(递归)【数据结构】

假设你已经知道了广义表长什么样(一堆括号、图像长得挺像二叉树。网课可以很快理解) 且对递归有一点熟悉了,

接下来我们审题:

 

广义表类型GList的定义:

  • typedef enum {ATOM, LIST} ElemTag;: 定义了一个枚举类型 ElemTag,其中 ATOM 表示原子元素,LIST 表示子表。

  • typedef struct GLNode { ... } *GList;: 定义了一个结构体 GLNode,并将其指针类型命名为 GList。这个结构体表示广义表的节点。

  • ElemTag tag: 表示节点的类型,可以是 ATOM 或 LIST

  • union { ... } un;: 定义了一个联合体 un,用于存储节点的数据。如果节点是 ATOM,则存储 char atom;如果节点是 LIST,则存储 struct { GLNode *hp, *tp; } ptr;,其中 hp 指向子表的头节点,tp 指向子表的尾节点。

要求实现以下函数:

  • int GListDepth(GList ls);: 这是一个函数声明,要求实现一个名为 GListDepth 的函数,该函数接受一个 GList 类型的参数 ls,并返回一个整数,表示广义表的深度。

广义表的定义

  • GList 是一个指向广义表节点的指针。

  • 每个节点有两种类型:ATOM 表示原子元素,LIST 表示子表。

  • 如果节点是 ATOM 类型,它包含一个字符 atom

  • 如果节点是 LIST 类型,它包含两个指针:hp 指向子表的头节点,tp 指向子表的尾节点(剩下元素的下一个节点,一般箭头向右。横着看像链表一样)。

广义表的深度

  • 广义表的深度是从根节点到最深子表的嵌套层数。

  • 例如,一个只包含原子元素的广义表的深度为1。

  • 如果广义表包含子表,则需要递归计算每个子表的深度,并取最大值。

好了,接下来看图我的注释

depth初始化随便设。

初始值为什么可以随意设定?

因为在递归的过程中,depth都会被重新赋值。所以它们的初始值无论是多少,都不会影响最终结果。

看一下代码:

一开始你声明了 depth1 和 depth2,但在紧接着的两行代码里,depth1 和 depth2 被赋值为递归调用的结果。所以,无论它们初始值是多少,在接下来的赋值操作中都会被覆盖。而在递归操作“递”的尽头,是开头return 1和return 0所给的初始值。也就是说,代码在每一次递归调用时,都会重新计算并设置 depth,之前的初始值不会对结果产生任何影响。

 

为什么需要if比较大小?

虽然广义表不是严格的二叉树,但它具有层次结构。通过递归调用,我们需要计算每个子表的深度,然后返回最大深度。以当前节点ls为起始,depth1 代表表头(向下箭头)部分的深度,而 depth2 代表表尾(向右箭头)部分的深度,只有取这两者的最大值,才能得到整个广义表的实际深度。否则,只考虑了表头或者表尾的一部分,可能会漏掉广义表中的深层嵌套结构。

A = (a, (b, c), d)

在这个例子里,A是一个表,里面有元素a,一个子表(b, c),还有d。我们要做的是计算这个表的深度,也就是有几层盒子被嵌套了。

表头(向下箭头hp)和表尾(向右箭头tp)
  • hp 就像你打开这个表后的第一个东西,可能是一个元素,也可能是另一个子表。比如这里的a
  • tp 是剩下的部分,也就是(b, c)d

再举个例子

A = ((a), (b, (c)), d)

比如这个例子,假设我们处在第一次递归,向下箭头会返回depth1 = 1(不是2,2是最后一次递归的“归”时+1,不必担心)这是因为表头是(a)。

而向右箭头,即剩下元素,才是真正能找到最深深度的地方。对,就是那个c。所以这要靠向右箭头的递归操作来记录。且如果向右箭头tp不跟向下箭头hp比较,岂不是a成了最深的地方?

 

if(!ls)

  return 1;

为什么要返回1,而不是返回0?

在递归算法中,ls为空(NULL)表示我们已经遍历到一个“没有内容”的地方,也就是递归的最底层。在计算广义表的深度时,这种空的情况代表一个“结束的层次”,因此返回1。

为什么返回1?你可以把空表看成一个特殊情况,虽然它是空的,但它仍然占据一层。因此,当tp指向NULL时,表示你已经遍历到这一层的最底部了,虽然没有更多内容,但广义表的结构还在,所以深度应该是1。

别忘了,你虽然进了这一层深度的链表,但还没给它计数呢,而这一行链表的深度如何结算?靠的就是最右边的NULL返回1。我们需要返回1,表示我们在这个层次已经“结束”了,准备通过递归的“归”一步步回到上一层。

如果这里返回0,那你会漏掉这一层空表的深度,导致计算出来的深度比实际的要少1层。

 

为什么GListDepth(ls->un.ptr.hp) + 1,而二叉树不用+1?

是因为广义表的深度计算涉及到子表的嵌套层次。具体来说,广义表的深度是从当前节点到最深子表的嵌套层数。 

+1 表示向下箭头方向当前节点是一个子表,需要在其子表头节点的深度基础上再加1 

其实和二叉树求深度没什么不同,只是左孩子得+1。但有些教学顺序(比如我这)是先学广义表,这其实挺不合理的

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值