广义表仍然属于单链表,是在单链表的基础上扩大应用范围而来的,即链表中的节点不仅可以是元素、数据,还可以是子表,一个新的子链表,子表也有自己的表头节点。用结构体变量描述链表节点,每个节点都有两个指针成员,一个指针成员指向本表广度方向的(即本行的)下一个节点,意义同单链表;另一个指针成员指向表深度方向对应的的子表首个元素节点,即若该位置元素是子表的话,该节点即是它所指向的子表的头节点。以共用体变量存储节点的原子数据或者深度指针。
广义链表的运算同单链表,一样包括建立链表,输出链表,还有求链表的广度与深度,求链表的所有原子个数。
广义链表的标准书写输出格式是,以括号()表示链表,链表内元素之间用逗号,分隔,
链表为空则用(#)表示,元素之间不允许存在空格,只能是一个逗号。
编写广义链表,大量应用递归知识。以下简称广义链表为链表。
建立链表,思路是从左往右扫描整个字符串(以为字符串建立链表为例),遇到原子则建立原子节点;遇到左括号(则建立子表表头;遇到逗号,建立下一个节点;遇到右括号),则表示本子表建立完成(也包括最外层的表)。这里要妥善处理字符指针的位置,对字符指针的移动要有理有据。精妙之处,见随后程序。
求链表长度的定义是最外层表的元素个数,这个简单。
求链表深度的递归定义是:表内所有元素的最大深度加1 。空表深度也为1.原子节点的深度定义为0.思路是我们要用循环遍历表内每一个元素,求出每个元素的深度。
输出链表:从头结点遍历表内所有节点,若本节点是原子节点则输出其对应字符,若其广度指针指向的节点不为null(或者说该节点同层的后一节点不为空),则输出一个逗号,继续输出其后面的节点,到了表尾则输出右括号)。若该节点是子表节点,则输出左括号,然后输出其深度指针指向的子表第一个元素节点,输出子表完毕,则输出右括号加以表示。这也是广义表的标准写法。
输出表的原子节点总个数,同理,我们给出其递归定义:等于首个原子节点后的表的剩余原子节点数目加1.若某一节点是子表表头,则该子表的原子总数也等于其第一个原子节点的后的表的原子节点总数加1.空节点的原子数为0.
递归解法,最难的是确定递归体,做到考虑问题的不重不漏。课本解法很经典,仔细记忆即可。递归程序不长,很简短,但空间复杂度大,不便于大脑发挥想象力模拟程序的正确性。
课本中还有一道例题,输出表中原子节点中ascii码最大的那个字符,假如链表存储的是字符。其递归思路仍是:比较表中第一个原子节点和剩下表中的最大节点,输出两者中的较大值。若第一个数据节点是子表表头,则求出子表的最大节点再接着继续与本层表中剩下节点比较。注意:不是比较表中第一个元素节点和第二个元素节点。遇到表尾的空指针则返回ascii 码0.
谢谢阅读。代码见下篇。我觉得理解思路挺重要的。具体的代码记不住,时间久了会忘,但理解了递归思路,解题思路,分析思路,就是忘了代码,还能自己重新组织出来代码。