编译原理习题3-9
编译原理习题3-9
✅ 3.9.1
Q(题目):
扩展图 3.58 的表格,加入下列操作符:
?
(0 次或 1 次)+
(1 次或多次)
Answer(答案):
节点 n | nullable(n) | firstpos(n) |
---|---|---|
n = c₁? |
true(因为可以为 ε) | firstpos(c₁) |
n = c₁+ |
nullable(c₁) | firstpos(c₁) |
Explanation(解释):
c₁?
表示字符 c₁ 可以出现 0 次或 1 次,因此一定 nullable(可为空)。c₁+
相当于c₁c₁*
,是否 nullable 取决于第一个 c₁ 是否 nullable。- 它们的 firstpos 都来自
c₁
,因为第一个出现的位置一定在c₁
中。
✅ 3.9.3 ⭐
Q(题目):
通过构造最小状态的 DFA,证明下列正则表达式是等价的:
(a|b)*
(a*|b*)*
((ε|a)b*)*
Answer(答案):
参见 3.7.3 和 3.9.2 中的最小 DFA 图,可知它们都生成相同语言:由任意数量的 a 和 b 组成的字符串,即 Σ*
(任意串)。
Explanation(解释):
这些表达式从形式上不同,但都允许任意数量的 a 和 b 交替、混合、重复,因此它们的最小 DFA 是相同的(只有一个循环状态接收所有输入)。
✅ 3.9.4 ⭐
Q(题目):
构造下列正则表达式的最小状态 DFA:
(a|b)*a(a|b)
(a|b)*a(a|b)(a|b)
(a|b)*a(a|b)(a|b)(a|b)
是否能发现规律?
Answer(答案):
- 每个正则表达式都表示:以任意个 a、b 开头,但必须包含一个特定长度的子串,其中首字符是 a。
- 每个表达式都必须识别最后一段特定模式。
表达式 | 最小状态数 |
---|---|
1 | 4 个状态 |
2 | 6 个状态 |
3 | 8 个状态 |
Pattern(规律):
对于正则 (a|b)*a(a|b)ⁿ
,DFA 至少需要 2n
个状态:
- 一个分支状态代表当前匹配到的位置;
- 一个状态记录历史信息,确保已经看到 “a” 之后的 n 个字符。
✅ 3.9.5 ⭐⭐
Q(题目):
正式证明:对正则 (a|b)*a(a|b)...(a|b)
,其中末尾有 n-1
个 (a|b)
,任何 DFA 至少需要 2n
个状态。
Hint 提示:
观察 3.9.4 的模式,每个状态记录了输入的历史信息。
Answer(答案):
我们构造 DFA 时需要记录:
- 是否已经匹配到了中间的
'a'
(这是转折点); - 接下来读入的每个字符都可能是 a 或 b,必须依次保存;
- 为了识别到最后一个字符是否完整匹配特定长度的尾串,DFA 需要为每种可能路径分配唯一状态。
因此:
- 共有
2n
个必要状态:- n 个状态记录“未匹配到最后 a”;
- n 个状态记录“匹配 a 后跟随 k 个字符(0 到 n-1)”。
Conclusion(结论):
为了处理这种历史相关的匹配任务,必须区分多种前缀路径,DFA 无法通过合并状态减少状态数,因此状态数下界为 2n
。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Totoroの旅!
评论