广义表深度定义为括号最大嵌套层数,空表()深度为1,原子深度为0,非空子表深度为1+子表最大深度;原子个数统计需穿透所有子表,原子计1、空表计0、子表递归累加。

广义表递归求深度:注意空表和子表的边界处理
广义表的深度定义为括号嵌套的最大层数,空表 () 深度为 1,原子不增加深度,而每个非空子表会带来一层嵌套。关键在于:遇到子表要递归进其内部,但必须把当前层的“1 +” 和子表返回值取最大,不能简单累加。
常见错误是把 depth = 1 + max_depth_of_sublists 写成 depth += ...,导致多层子表被重复加;或者忽略空表——() 是合法广义表,它没有子节点,但深度仍是 1。
- 递归入口统一用一个
getDepth()成员函数,对空表直接返回 1 - 遍历表头时,若当前元素是子表(即
isList() == true),调用其getDepth()并参与max计算 - 原子节点(
isAtom() == true)不贡献深度,跳过 - 初始调用前确保表结构已正确解析,否则
getDepth()可能访问空指针
示例片段(假设节点类型为 GListNode,含 isList()、getSublist()、next):
int GListNode::getDepth() const {
if (!this) return 0;
if (isAtom()) return 0; // 原子无深度
if (isEmpty()) return 1; // () → 深度 1
int maxSubDepth = 0;
for (auto p = getFirst(); p; p = p->next) {
if (p->isList()) {
maxSubDepth = std::max(maxSubDepth, p->getSublist()->getDepth());
}
}
return 1 + maxSubDepth;
}
统计原子个数:递归展开所有层级,只计非子表节点
原子个数就是广义表中所有不可再分的元素总数,包括数字、字符、字符串等,但不含任何 () 或嵌套结构。难点在于:子表本身是节点,但它的内容才含原子,所以必须「穿透」每一层子表调用统计,而不能只看当前层。
立即学习“C++免费学习笔记(深入)”;
典型误操作是只遍历首层节点,漏掉深层嵌套里的原子;或把空表 () 当作一个原子计数(实际它不含原子,应计 0)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 原子节点:直接计 1
- 空表节点:
isEmpty() == true→ 返回 0 - 非空子表节点:递归调用其
countAtoms(),结果累加 - 务必区分「节点类型」和「节点内容」——
isList()为真时,需取getSublist()再统计,而不是给这个节点本身加 1
简写示意:
int GListNode::countAtoms() const {
if (!this) return 0;
if (isAtom()) return 1;
if (isEmpty()) return 0;
int cnt = 0;
for (auto p = getFirst(); p; p = p->next) {
if (p->isAtom()) cnt++;
else if (p->isList()) cnt += p->getSublist()->countAtoms();
}
return cnt;
}
递归终止条件不一致:深度和原子数的 base case 必须分开设计
这是最容易混淆的点:同一个空表 (),对深度返回 1,对原子数返回 0;同一个原子节点,对深度返回 0,对原子数返回 1。如果共用一套判断逻辑(比如都用 if (isAtom()) return 1;),必然出错。
必须严格按语义分离:
-
getDepth()的 base:原子 → 0,空表 → 1,非空子表 → 1 + max(各子表深度) -
countAtoms()的 base:原子 → 1,空表 → 0,非空子表 → 各子表原子数之和 - 两者都不应在原子分支里再调用递归,也不应在空表分支里进入循环
若使用统一节点类,建议两个函数完全独立实现,不要提取公共递归框架——表面省代码,实则埋雷。
C++ 实现时要注意内存模型和遍历安全
广义表通常用链表+联合体(union)或多态指针实现,递归过程中容易因裸指针未判空、循环引用(如表包含自身)导致栈溢出或崩溃。
- 所有指针访问前加
if (!ptr) return 0;,尤其getFirst()、next、getSublist() - 避免在
getDepth()中修改节点状态,否则可能影响后续countAtoms()调用 - 若表结构支持共享子表(如 DAG 形式),需引入 visited 标记防止无限递归——但标准广义表定义不允许循环,一般可不加,除非你明确允许
- 用智能指针(如
std::shared_ptr<GListNode>)管理生命周期,比裸指针更安全,尤其在多次递归调用中
深度和原子数看似简单,真正卡住人的永远是空表语义、指针空解引用、以及两个函数对同一结构做出不同解释的惯性思维。

















