广义表C/C++实现详解

所谓的广义表就是单链表的扩展,就是节点可以是一个元素也可以是一个链表。官方的说法是,原子节点和子表节点。广义表用递归的方法来创建是最简单易懂的,也符合广义表的思想。

C代码实现下载
C++代码实现下载
(备用下载地址 )

1.广义表的各种形态

(1)、A = (); 空表
(2)、B = (()); 长度为1,深度为2,原子个数为0,这个实质上就是广义表中有一个元素,它是子表,该子表为空。
(3)、C = (a); 长度为1,深度为0,原子个数为1
(4)、D = (a,A,b);长度为3,深度为2,原子个数为2,其中A是一个空表。
(5)、E = (A,B,C,D);长度为4,深度为3,原子个数为3,其中ABCD都是表。
(6)、F = (a,F); 无限递归下去。

2.广义表C语言实现思路

先来看结构体定义

enum NodeType { ATOM, LIST };

typedef struct _GList
{
    NodeType nodeType;   //节点类型
    union
    {
        char c;          //原子 
        _GList* subList; //子表
    };
    _GList* next;       //指向后继节点
}GList, *PGList;

(1)创建表
给定一个串,该串必须遵守相关规则,例如,层次分隔符用‘()’,元素分隔符用‘,’。

伪代码描述如下:

Create(PGList* gl,char* s)
{
    如果s="()",则(*gl)=NULL
    如果s='(',则递归创建子表,Create(&(*gl)->subList,s);
    否则创建原子节点

    如果s=',',则递归创建后继节点(该节点可能是ATOMLISTCreate(&(*gl)->next,s);
    如果s=')',则置(*gl)->next为NULL,表示该子表已经结束
    如果s='\0',则置(*gl)->next为NULL,表示该广义表已经创建完成
}

重点!!! :为什么这里要传进去二级指针?刚开始我传进一级指针的时候,我发现创建完成后,gl = NULL,为什么?因为没有一个变量记录gl第一个节点的地址啊,所以最后找不到它了。这时候就需要一个二级指针,指向该头节点的地址。如图:

(2)计算广义表长度
这个就比较简单了,就和单链表一样,依次遍历第一层节点即可。
需要注意的是,因为创建广义表的时候,一开始就创建了一个子表节点,所以该节点才是广义表的头节点。

(3)计算广义表深度
递归遍历子表,取子表深度最大值。例如:(A,(B,C),(D,E,(F,G)),H)
此时最大深度在(F,G)这个子表处得到。

(4)添加原子到广义表前面或后面
这个操作和单链表的操作是一样的,广义表如果要实现更深层次的插入和添加会比较麻烦。

(5)打印广义表
一样的递归遍历,若是原子节点,则直接输出,所示子表节点,则递归进去。

2.广义表C++实现思路

广义表的节点类如下:

enum NodeType { ATOM, LIST };   //节点类型
private:
    class Node   //广义表结点类
    {
    public:
        Node(NodeType nodeType, T atom)
            :nodeType(nodeType), atom(atom) {}
    private:
        NodeType nodeType;      //节点类型
        union
        {
            T atom;             //原子
            Node* subList;      //子表
        };
        Node* next;             //指向下一个元素
        friend class GList;
    };

和C语言类似。

只不过C++我用模板实现,这样就能存储字符、整形、浮点型了。
基本思路和C语言类似,所以,我一般都是用C语言实现了简单的功能,然后用C++封装成一个完善的类。这里省略对C++的描述,具体看代码,里面有注释。

猜你喜欢

转载自blog.csdn.net/qq_18297675/article/details/61618193