广义表
资料:https://pan.quark.cn/s/43d906ddfa1b、https://pan.quark.cn/s/90ad8fba8347、https://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。
广义表的核心特征:
- 层次性:支持嵌套结构,子表可继续包含原子或子表;
- 共享性:多个广义表可共享同一个子表(避免重复存储);
- 递归性 :广义表可以是自身的子表(如
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
五、广义表的典型应用
- 数据结构表示:用于表示复杂的嵌套数据,如 XML/JSON 数据的底层解析(JSON 的数组/对象嵌套本质是广义表);
- 表达式解析 :表示算术表达式的嵌套结构,如
(1 + (2 × 3))可表示为广义表(+, 1, (×, 2, 3)); - 树结构的存储 :树的嵌套结构可直接映射为广义表,如二叉树
1(2(3),4)可表示为(1, (2, 3), (4)); - 编译器语法分析:用于表示程序的语法树(嵌套的语法单元);
- 图形学:表示复杂的几何形状(嵌套的点、线、面结构)。
六、广义表与线性表的对比
| 特性 | 线性表 | 广义表 |
|---|---|---|
| 元素类型 | 仅原子 | 原子 + 子表(嵌套) |
| 结构复杂度 | 一维线性结构 | 多维嵌套结构 |
| 存储方式 | 数组/单链表 | 混合链式结构(双节点) |
| 核心操作 | 增删改查(线性) | 递归遍历、求深度/长度 |
| 适用场景 | 简单有序数据 | 复杂嵌套数据 |
广义表是线性表的泛化,弥补了线性表仅能存储原子的不足,是处理嵌套、层次化数据的核心数据结构,但由于递归和嵌套特性,实现和操作复杂度远高于普通线性表。