数据结构:广义表

广义表

资料:https://pan.quark.cn/s/43d906ddfa1bhttps://pan.quark.cn/s/90ad8fba8347https://pan.quark.cn/s/d9d72152d3cf

一、广义表的定义

广义表(Generalized List)是线性表的扩展,是由零个或多个原子(Atom)或子表(SubList) 组成的有序序列,记为:
LS=(a1,a2,...,an) LS = (a_1, a_2, ..., a_n) LS=(a1,a2,...,an)

其中:

  • nnn 为广义表的长度,n=0n=0n=0 时称为空表;
  • aia_iai 既可以是原子 (不可再分的基本元素,如数字、字符),也可以是子表(另一个广义表);
  • 广义表的深度 :指表中嵌套的最大层数,原子的深度为 0,空表的深度为 1,例如 ((1,2), (3,(4))) 的深度为 3。

广义表的核心特征:

  1. 层次性:支持嵌套结构,子表可继续包含原子或子表;
  2. 共享性:多个广义表可共享同一个子表(避免重复存储);
  3. 递归性 :广义表可以是自身的子表(如 LS = (LS, 1))。

二、广义表的核心概念

1. 基本术语

术语 定义示例(以 LS=(a,(b,c),d)LS = (a, (b, c), d)LS=(a,(b,c),d) 为例)
表头(Head) 广义表的第一个元素,Head(LS)=aHead(LS) = aHead(LS)=a(原子);若 LS=((1,2),3)LS = ((1,2), 3)LS=((1,2),3),则 Head(LS)=(1,2)Head(LS) = (1,2)Head(LS)=(1,2)(子表)
表尾(Tail) 广义表去掉表头后剩余元素组成的子表,Tail(LS)=((b,c),d)Tail(LS) = ((b, c), d)Tail(LS)=((b,c),d)(始终是一个广义表)
长度 最外层元素的个数,Length(LS)=3Length(LS) = 3Length(LS)=3
深度 嵌套的最大层数,Depth(LS)=2Depth(LS) = 2Depth(LS)=2

2. 特殊广义表

  • 空表(),长度为 0,深度为 1;
  • 纯原子表 :无嵌套的广义表,等价于普通线性表,如 (1, 2, 3)
  • 递归表 :包含自身的广义表,如 LS = (LS, 5)
  • 共享表 :子表被多个父表引用,如 A=(1,2), B=(A, 3)(A 是 B 的共享子表)。

3. 表头/表尾特性

  • 任何非空广义表的表头 可以是原子或子表,表尾一定是广义表(即使只剩一个元素,表尾也是空表);
  • 示例:
    • (1,2,3),表头是 1,表尾是 (2,3)
    • ((1),2),表头是 (1),表尾是 (2)
    • (a),表头是 a,表尾是 ()

三、广义表的存储结构

广义表的嵌套特性决定了其无法用普通数组存储,通常采用链式存储,核心思路是:用两种节点(原子节点、表节点)表示不同元素,通过指针连接。

1. 节点结构设计

复制代码
# 通用节点结构(Python 类表示)
class GLNode:
    def __init__(self, tag):
        self.tag = tag  # 标记:0 表示原子节点,1 表示表节点
        if tag == 0:
            self.data = None  # 原子节点:存储原子值
        else:
            self.head = None  # 表节点:指向子表的表头
        self.tail = None     # 所有节点:指向当前元素的下一个元素(表尾)
  • 原子节点(tag=0)data 存储原子值(如 1、'a'),tail 指向同一层的下一个元素;
  • 表节点(tag=1)head 指向子表的第一个节点,tail 指向同一层的下一个元素。

2. 存储示例

以广义表 LS = (a, (b, c), d) 为例,链式存储结构如下:

复制代码
表节点(1) → 原子节点(0, a) → 表节点(1) → 原子节点(0, d) → None
            ↓ (tail)        ↓ (tail)        ↓ (tail)
                          原子节点(0, b) → 原子节点(0, c) → None
                          ↓ (head)        ↓ (tail)        ↓ (tail)

四、广义表的核心操作

1. 基本操作列表

操作 描述 核心思路
构建广义表 从字符串(如 "(a,(b,c),d)")生成链式结构 递归解析字符串,遇到 ( 则创建表节点,遇到原子则创建原子节点,处理逗号和 ) 分割元素
求长度 统计最外层元素个数 遍历最外层节点,计数(跳过嵌套子表的内部节点)
求深度 计算嵌套的最大层数 递归:原子深度为 0,表节点深度为子表深度 + 1,取所有元素的最大深度
取表头 获取第一个元素 非空表的第一个节点(原子/表节点)
取表尾 获取去掉表头后的子表 非空表的第一个节点的 tail 指针指向的结构
遍历广义表 按层次输出所有元素 递归遍历:原子节点输出值,表节点递归遍历其子表

2. 实现示例(Python)

python 复制代码
class GLNode:
    """广义表节点类"""
    def __init__(self, tag):
        self.tag = tag  # 0: 原子节点,1: 表节点
        self.data = None  # 原子节点的数据
        self.head = None  # 表节点的表头指针
        self.tail = None  # 指向下一个元素的指针

class GeneralizedList:
    """广义表类"""
    def __init__(self):
        self.head = None  # 广义表的头节点(表节点)
    
    def _parse(self, s, idx):
        """递归解析字符串,返回当前节点和更新后的索引"""
        # 跳过空格
        while idx < len(s) and s[idx] == ' ':
            idx += 1
        if idx >= len(s) or s[idx] == ')':
            return None, idx + 1  # 空表或表结束
        
        if s[idx] == '(':
            # 创建表节点
            node = GLNode(tag=1)
            idx += 1  # 跳过 '('
            # 解析表头
            node.head, idx = self._parse(s, idx)
            # 解析表尾(递归处理后续元素)
            current = node.head
            while current is not None and idx < len(s) and s[idx] != ')':
                # 跳过逗号
                while idx < len(s) and s[idx] == ',':
                    idx += 1
                # 解析下一个元素
                next_node, idx = self._parse(s, idx)
                if next_node is not None:
                    current.tail = next_node
                    current = next_node
            return node, idx
        else:
            # 创建原子节点(提取连续的原子字符)
            atom = []
            while idx < len(s) and s[idx] not in ',() ':
                atom.append(s[idx])
                idx += 1
            node = GLNode(tag=0)
            node.data = ''.join(atom)
            return node, idx
    
    def build_from_string(self, s):
        """从字符串构建广义表(如 "(a,(b,c),d)")"""
        if s.strip() == '()':
            self.head = GLNode(tag=1)
            return
        self.head, _ = self._parse(s, 0)
    
    def _get_length(self, node):
        """递归求长度(辅助函数)"""
        if node is None:
            return 0
        return 1 + self._get_length(node.tail)
    
    def get_length(self):
        """求广义表的长度(最外层元素个数)"""
        if self.head is None or self.head.tag != 1:
            return 0
        return self._get_length(self.head.head)
    
    def _get_depth(self, node):
        """递归求深度(辅助函数)"""
        if node is None:
            return 1  # 空表深度为1
        if node.tag == 0:
            return 0  # 原子深度为0
        # 表节点:深度 = 子表深度 + 1,取最大值
        max_depth = 0
        current = node.head
        while current is not None:
            current_depth = self._get_depth(current)
            if current_depth > max_depth:
                max_depth = current_depth
            current = current.tail
        return max_depth + 1
    
    def get_depth(self):
        """求广义表的深度"""
        if self.head is None:
            return 0
        return self._get_depth(self.head)
    
    def _traverse(self, node, result):
        """递归遍历(辅助函数)"""
        if node is None:
            return
        if node.tag == 0:
            # 原子节点,添加值
            result.append(node.data)
        else:
            # 表节点,递归遍历子表
            result.append('(')
            self._traverse(node.head, result)
            result.append(')')
        # 遍历下一个元素
        if node.tail is not None:
            result.append(',')
            self._traverse(node.tail, result)
    
    def traverse(self):
        """遍历广义表,返回字符串形式"""
        result = []
        if self.head is None:
            return "()"
        self._traverse(self.head, result)
        return ''.join(result)

# 使用示例
if __name__ == "__main__":
    # 构建广义表
    gl = GeneralizedList()
    gl.build_from_string("(a, (b, c), d)")
    
    # 输出基本信息
    print("广义表结构:", gl.traverse())  # 输出 (a,(b,c),d)
    print("长度:", gl.get_length())      # 输出 3
    print("深度:", gl.get_depth())      # 输出 2
    
    # 测试空表
    gl_empty = GeneralizedList()
    gl_empty.build_from_string("()")
    print("空表深度:", gl_empty.get_depth())  # 输出 1
    print("空表长度:", gl_empty.get_length())  # 输出 0
    
    # 测试嵌套表
    gl_nested = GeneralizedList()
    gl_nested.build_from_string("((1, 2), (3, (4)), 5)")
    print("嵌套表结构:", gl_nested.traverse())  # 输出 ((1,2),(3,(4)),5)
    print("嵌套表深度:", gl_nested.get_depth())  # 输出 3

五、广义表的典型应用

  1. 数据结构表示:用于表示复杂的嵌套数据,如 XML/JSON 数据的底层解析(JSON 的数组/对象嵌套本质是广义表);
  2. 表达式解析 :表示算术表达式的嵌套结构,如 (1 + (2 × 3)) 可表示为广义表 (+, 1, (×, 2, 3))
  3. 树结构的存储 :树的嵌套结构可直接映射为广义表,如二叉树 1(2(3),4) 可表示为 (1, (2, 3), (4))
  4. 编译器语法分析:用于表示程序的语法树(嵌套的语法单元);
  5. 图形学:表示复杂的几何形状(嵌套的点、线、面结构)。

六、广义表与线性表的对比

特性 线性表 广义表
元素类型 仅原子 原子 + 子表(嵌套)
结构复杂度 一维线性结构 多维嵌套结构
存储方式 数组/单链表 混合链式结构(双节点)
核心操作 增删改查(线性) 递归遍历、求深度/长度
适用场景 简单有序数据 复杂嵌套数据

广义表是线性表的泛化,弥补了线性表仅能存储原子的不足,是处理嵌套、层次化数据的核心数据结构,但由于递归和嵌套特性,实现和操作复杂度远高于普通线性表。

相关推荐
我在人间贩卖青春2 小时前
线性表之循环队列
数据结构·队列·循环队列
仁桃仁呀2 小时前
160.相交链表
数据结构·算法·链表
良木生香3 小时前
【数据结构-初阶】详解栈和队列(1)---栈
c语言·数据结构·算法·蓝桥杯
tang&3 小时前
双指针算法:化繁为简的优雅解法
数据结构·c++·算法
Aaron15883 小时前
RFSOC+VU13P在无线信道模拟中的技术应用分析
数据结构·人工智能·算法·fpga开发·硬件架构·硬件工程·射频工程
咸鱼加辣3 小时前
“刻意强调” O(1)
数据结构·算法
LYFlied4 小时前
【每日算法】LeetCode 146. LRU 缓存机制
前端·数据结构·算法·leetcode·缓存
LYFlied4 小时前
【每日算法】LeetCode142. 环形链表 II
数据结构·算法·leetcode·链表
LYFlied4 小时前
【每日算法】LeetCode 23. 合并 K 个升序链表
前端·数据结构·算法·leetcode·链表