正则语言与有限自动机

ZaynPei Lv6

计算模型:有限自动机 (Finite Automata)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
有限自动机(Finite Automata,简称 **FA** 或 FSM)是一种基础的计算模型。它拥有**有限数量的状态**,并且**没有额外的可读写存储**。自动机从初始状态出发,逐步读取输入字符串的每个符号,根据**当前状态**和**输入符号**通过**状态转移函数**切换到**下一个状态**。输入处理完毕后,若停在某个**接受状态**,则该字符串被自动机接受。

它的主要任务是**判断**一个**给定的输入字符串** $w$ 是否属于**它所定义的语言** $L(M)$, 即 $w \in L(M)$。 这里的$L(M)$ 也就是该自动机对应的**正则语言**。

有限自动机分为两类:**确定性有限自动机** (DFA) 和**非确定性有限自动机** (NFA)。

### 确定性有限自动机 (DFA)

确定性有限自动机(DFA)在每一步计算中,当前状态和输入符号**唯一决定**下一个状态。

**形式化定义:**
DFA 可表示为五元组 $M = (K, \Sigma, \delta, s, F)$,其中:

- $K$:有限状态集合, $K = \{q_0, q_1, \ldots, q_{n-1}\}$
- $\Sigma$:输入字母表, 一个有限符号集合, 如 $\Sigma = \{a, b\}$
- $\delta$:状态转移函数,$\delta: K \times \Sigma \to K$ , 定义了在状态 $q \in K$ 下读取输入符号 $a \in \Sigma$ 时,自动机转移到的下一个状态 $\delta(q, a)$
- $s \in K$:初始状态, $M$ 开始计算时所在的状态
- $F \subseteq K$:接受状态集合, 如果计算结束时自动机停在 $F$ 中的某个状态,则输入字符串被接受。

![alt text](image.png)

需要注意的是, 假如已知 $M$ 接受 $L$ , 它的补集 $\overline{L}$ 也可以被一个DFA接受, 只需将 $M$ 的接受状态和非接受状态互换即可。
![alt text](image-1.png)
#### 运算过程

我们已经定义了机器的结构,现在来看它的运算过程。

- **配置 (Configuration):** DFA 的配置由**当前状态**和**尚未读取的输入字符串**组成,记为序对 $(q, w)$。
- **一步产生关系 ($\vdash_M$):** 若机器在状态 $q$,输入字符串为 $aw'$,且 $\delta(q, a) = q'$,则 $(q, aw') \vdash_M (q', w')$,表示机器从配置 $(q, aw')$ 一步转移到 $(q', w')$。
- **多步产生关系 ($\vdash_M^*$):** 表示零步或多步的产生关系,是 $\vdash_M$ 的**自反传递闭包**。例如,$(n, WSSW) \vdash_M^* (n, \epsilon)$ 表示从初始状态 $n$ 处理完整输入 $WSSW$ 后停在状态 $n$。
- **字符串的接受:** 字符串 $w$ 被 $M$ 接受,当且仅当,从初始配置 $(s, w)$ 出发,经过若干步计算到达某个配置 $(q, \epsilon)$,且 $q$ 属于接受状态集合 $F$。


### 非确定性有限自动机 (NFA)

非确定性有限自动机(NFA)允许在**某个状态**和**输入符号**下有**多个可能的下一个状态**,也可能**没有可选状态**(计算终止)。NFA 还支持 $\varepsilon$-转移,即可以在**不消耗输入符号的情况下进行状态转换**。即 NFA 的三大特点:多重选择, 没有选择, 空串转移。

**接受条件:**
一个字符串 $w$ 被 NFA 接受,当且仅当存在**至少一条合法的计算路径**,在消耗完 $w$ 后,自动机停在某个接受状态。

![alt text](image-2.png)

如上的正则表达式要识别 $L=(ab \cup aba)^*$ , 可以选择DFA来实现, 但是显然状态数更多, 可读性更差. 而使用NFA可以更简洁地表示该语言.

> 在DFA中, 像 $q_4$ 这样的状态,虽然在识别正确的语言中没有使用到, 但是仍然具有非常重要的功能,它通常被称为死状态(Dead State)或陷阱状态(Trap State)。
> 当自动机进入死状态后,无论接收到什么输入符号,都会一直停留在该状态,无法再转移到其他状态。死状态的存在保证了 DFA 的确定性和完整性,并处理无效的输入序列。

对于NFA, 其形式化定义与DFA类似, 但**状态转移函数**有所不同: DFA的状态转移函数 $\delta$ 是一个确定性的映射,而 NFA 的状态转移函数 $\delta$ 则是一个**非确定性的映射**(或者说是一种**关系**),允许多个可能的下一个状态。

NFA 可表示为五元组 $M = (K, \Sigma, \delta, s, F)$,其中:
- $K$:有限状态集合, $K = \{q_0, q_1, \ldots, q_{n-1}\}$
- $\Sigma$:输入字母表, 一个有限符号集合, 如 $\Sigma = \{a, b\}$
- $\delta$:状态转移函数,$\delta: K \times (\Sigma \ \cup \{\varepsilon\}) \to P(K)$ , 定义了在状态 $q \in K$ 下读取输入符号 $a \in \Sigma$ 或 $\varepsilon$ 时,自动机可以转移到的**下一个状态集合** $\delta(q, a) \subseteq K$
- $s \in K$:初始状态, $M$ 开始计算时所在的状态
- $F \subseteq K$:接受状态集合, 如果计算结束时自动机停在 $F$ 中的某个状态,则输入字符串被接受。

至于其运算过程, 与DFA类似, 只是需要考虑多条路径的情况.

![alt text](image-3.png)

### DFA 与 NFA 的等价性

DFA 和 NFA 在**描述语言的能力**上是完全等价的。也就是说,任何可以被 NFA 接受的语言,也可以被某个等价的 DFA 接受,反之亦然。

且任意DFA都可以转换为等价的NFA, 反之亦然. 但NFA转换为DFA时, 可能会导致状态数指数级增长.

首先, 任意DFA都可以看作是特殊的NFA, 因为DFA的每个状态和输入符号下只有一个确定的下一个状态, 这正是NFA的一种特例. 而证明NFA可以转换为DFA, 我们需要使用下面的子集构造法

**证明核心:子集构造法 (Subset Construction)**

首先, DFA和NFA有两个重要的区别:
1. NFA允许多个可能的下一个状态,而DFA在每一步只有一个确定的下一个状态。也就是两者的形式化定义中, 状态转移函数 $\delta$ 的不同:
- 对于DFA: $\delta: K \times \Sigma \to K$
- 对于NFA: $\delta: K \times (\Sigma \cup \{\varepsilon\}) \to P(K)$
2. NFA允许$\varepsilon$-转移,而DFA不允许。即:
- 对于DFA: 没有$\varepsilon$-转移
- 对于NFA: 允许$\varepsilon$-转移, 即 $\delta(q, \varepsilon)$ 可以非空

下面我们的转换的核心就是处理这两个区别.

我们不再追踪 NFA “可能”处于的单一状态,而是追踪它在任何时刻“可能处于的所有状态的集合”。具体来说,**子集构造法**的核心思想是:构造一台新的 DFA,使其每个状态都对应于原 NFA 的一个**状态集合**。

> 为了解决 NFA 中的 $\varepsilon$-转移(即无需消耗输入即可转移),我们引入$\varepsilon$-闭包(epsilon-closure),记作 $E(q)$。$E(q)$ 表示:从**状态 $q$ 出发**,**仅通过 $\varepsilon$-转移**(不读取任何输入),能够到达的**所有状态的集合**(包括 $q$ 本身)。

#### 子集构造法步骤

假设有一台 NFA $M$,我们要构造一台等价的 DFA $M'$,其定义如下:

- **状态集 $K'$**:$M'$ 的每个状态是 $M$ 的状态集的一个子集(即 $K'$ 是 $K$ 的幂集)。
- $K' = P(K) = 2^K$
- 从这里可以看出, 如果NFA有 $n$ 个状态, 则对应的DFA最多有 $2^n$ 个状态, 也就是复杂度的指数级增长. 不过很多状态是不可达的, 因此实际状态数通常远**小于 $2^n$**.
- **初始状态 $s'$**:$M'$ 的初始状态是 $M$ 的初始状态 $s$ 的 $\varepsilon$-闭包,即 $E(s)$。
- $s' = E(s)$
- **字母表 $\Sigma$**:与 NFA 相同。
- **转移函数 $\delta'$**:对于 $M'$ 的任意状态 $Q \subseteq K$ 和输入符号 $a$,其转移定义为:$\delta'(Q, a) = \bigcup_{q \in Q} E(\delta(q, a))$
1. 对 **$Q$ 中每个状态 $q$**,计算 $q$ 读入 $a$ 后能到达的所有状态的集合 $S$。
2. 对 $S$ 中每个状态,取其 **$\varepsilon$-闭包**。
3. 取所有这些 $\varepsilon$-闭包的**并集**,作为 $M'$ 在 $Q$ 读入 $a$ 后的下一个状态。
- 一般来说, DFA 的状态集 $K'$ 是通过一种按需计算的方式构建的。从起始状态开始, 根据输入符号逐步计算和添加新的状态子集, 接着利用得到的状态子集继续计算, 直到不再有新的状态子集被发现为止。
- **接受状态 $F'$**:$M'$ 的接受状态集合是**所有**包含 $M$ 至少一个接受状态的状态子集。
- $F' = \{Q \subseteq K \mid Q \cap F \neq \emptyset\}$

这种方法保证了 DFA 能“模拟”NFA 的所有可能路径,从而接受与原 NFA 相同的语言。

#### 示例

![alt text](image-4.png)
![alt text](image-5.png)

**第一步:NFA $M$ 定义整理与 $\varepsilon$-闭包预计算**

- 状态集 $K$:$\{q_0, q_1, q_2, q_3, q_4\}$
- 字母表 $\Sigma$:$\{a, b\}$
- 起始状态 $s$:$q_0$
- 接受状态 $F$:$\{q_4\}$
- 转移关系 $\Delta$:

- 非 $\varepsilon$ 转移:
- $\delta(q_0, b) = \{q_2\}$
- $\delta(q_2, b) = \{q_4\}$
- $\delta(q_1, a) = \{q_0, q_4\}$
- $\delta(q_3, a) = \{q_4\}$
- $\varepsilon$ 转移:
- $\delta(q_0, \varepsilon) = \{q_1, q_2, q_3\}$
- $\delta(q_1, \varepsilon) = \{q_2, q_3\}$
- $\delta(q_4, \varepsilon) = \{q_3\}$

- $\varepsilon$-闭包计算:
- $E(q_2) = \{q_2\}$
- $E(q_3) = \{q_3\}$
- $E(q_4) = \{q_3, q_4\}$
- $E(q_1) = \{q_1, q_2, q_3\}$
- $E(q_0) = \{q_0, q_1, q_2, q_3\}$

**第二步:构造 DFA $M'$ 的状态和转移**

我们从 DFA 的初始状态开始,采用按需计算的方式,逐步构建 DFA 的状态集和转移函数。

DFA **初始状态** $s'$ = $A = E(q_0) = \{q_0, q_1, q_2, q_3\}$(非接受状态)

接着从状态 $A$ 开始,计算它对每个输入符号的转移。

- **处理状态 $A = \{q_0, q_1, q_2, q_3\}$**
- $\delta'(A, a)$ 的计算:
- NFA 目标状态:$\delta(q_1, a) \cup \delta(q_3, a) = \{q_0, q_4\} \cup \{q_4\} = \{q_0, q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_0) \cup E(q_4) = \{q_0, q_1, q_2, q_3\} \cup \{q_3, q_4\} = \mathbf{\{q_0, q_1, q_2, q_3, q_4\}}$
- 得到新状态 $B = \{q_0, q_1, q_2, q_3, q_4\}$。$B$ 包含 $q_4$,因此是接受状态。
- $\delta'(A, b)$ 的计算:
- NFA 目标状态:$\delta(q_0, b) \cup \delta(q_2, b) = \{q_2\} \cup \{q_4\} = \{q_2, q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_2) \cup E(q_4) = \{q_2\} \cup \{q_3, q_4\} = \mathbf{\{q_2, q_3, q_4\}}$
- 得到新状态 $C = \{q_2, q_3, q_4\}$。$C$ 包含 $q_4$,因此是接受状态。

- **处理状态 $B = \{q_0, q_1, q_2, q_3, q_4\}$**
- $\delta'(B, a)$ 的计算:
- NFA 目标状态:$\delta(q_1, a) \cup \delta(q_3, a) = \{q_0, q_4\} \cup \{q_4\} = \{q_0, q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_0) \cup E(q_4) = \{q_0, q_1, q_2, q_3, q_4\} = \mathbf{B}$
- 转移到自身。
- $\delta'(B, b)$ 的计算:
- NFA 目标状态:$\delta(q_0, b) \cup \delta(q_2, b) = \{q_2\} \cup \{q_4\} = \{q_2, q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_2) \cup E(q_4) = \{q_2\} \cup \{q_3, q_4\} = \mathbf{C}$
- 转移到状态 $C$。

- **处理状态 $C = \{q_2, q_3, q_4\}$**
- $\delta'(C, a)$ 的计算:
- NFA 目标状态:$\delta(q_3, a) = \{q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_4) = \mathbf{\{q_3, q_4\}}$
- 得到新状态 $D = \{q_3, q_4\}$。$D$ 包含 $q_4$,因此是接受状态。
- $\delta'(C, b)$ 的计算:
- NFA 目标状态:$\delta(q_2, b) = \{q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_4) = \mathbf{\{q_3, q_4\}}$
- 转移到状态 $D$。

- **处理状态 $D = \{q_3, q_4\}$**
- $\delta'(D, a)$ 的计算:
- NFA 目标状态:$\delta(q_3, a) = \{q_4\}$
- 取 $\varepsilon$-闭包并集:$E(q_4) = \mathbf{\{q_3, q_4\}} = \mathbf{D}$
- 转移到自身。
- $\delta'(D, b)$ 的计算:
- NFA 目标状态:$\emptyset$
- 取 $\varepsilon$-闭包并集:$\mathbf{\emptyset}$
- 得到新状态 $E = \emptyset$(死状态)。$E$ 不包含 $q_4$,因此不是接受状态。

- **处理状态 $E = \emptyset$(死状态)**
- $\delta'(E, a) = \emptyset = \mathbf{E}$
- $\delta'(E, b) = \emptyset = \mathbf{E}$

所有可达状态都已计算完毕。

第三步:最终的 DFA $M'$状态集

- **状态集 $K'$**:
$\{A, B, C, D, E\}$
- $A = \{q_0, q_1, q_2, q_3\}$
- $B = \{q_0, q_1, q_2, q_3, q_4\}$
- $C = \{q_2, q_3, q_4\}$
- $D = \{q_3, q_4\}$
- $E = \emptyset$

- **初始状态 $s'$**:$A$

- **接受状态 $F'$**:$\{B, C, D\}$, 因为含有 $q_4$。

- **转移函数 $\delta'$(表格形式):**

| 状态 | $a$ | $b$ | 接受 |
|------|-----|-----|------|
| $A$ | $B$ | $C$ | 否 |
| $B$ | $B$ | $C$ | 是 |
| $C$ | $D$ | $D$ | 是 |
| $D$ | $D$ | $E$ | 是 |
| $E$ | $E$ | $E$ | 否 |

这样,原 NFA 被转换为等价的 DFA,所有状态和转移均已明确。

## 语言表示:正则表达式 (Regular Expressions)

正则表达式是一种用于描述语言的代数工具。其核心思想是:从**最基本的语言**(如空语言 $\emptyset$ 和单符号语言 $\{a\}$)出发,通过**三种基本运算**构造更复杂的语言。

一个正则表达式 $\alpha$ 及其表示的语言 $L(\alpha)$ 递归定义如下:

- 基础情况:
- $\emptyset$ 是正则表达式,表示空语言 $L(\emptyset) = \emptyset$
- 对于字母表 $\Sigma$ 中的每个符号 $a$,$a$ 是正则表达式,表示语言 $L(a) = \{a\}$
- 归纳步骤:若 $\alpha$ 和 $\beta$ 都是正则表达式,则
- 连接 (Concatenation):$(\alpha\beta)$ 是正则表达式,表示语言 $L((\alpha\beta)) = L(\alpha)L(\beta)$
- 并 (Union):$(\alpha \cup \beta)$ 是正则表达式,表示语言 $L((\alpha \cup \beta)) = L(\alpha) \cup L(\beta)$
- Kleene 星号 (Kleene Star):$\alpha^*$ 是正则表达式,表示语言 $L(\alpha^*) = L(\alpha)^*$,即 $L(\alpha)$ 中 0 个或多个字符串的所有连接

**正则语言**的定义:所有**能够用正则表达式描述的语言**称为正则语言。

下面是一个定理: **一个语言是正则的,当且仅当它能被一台有穷自动机接受**。


这是一个“当且仅当”的命题,所以我们需要从两个方向来证明。
- 方向一:如果一个语言是正则的,那么它一定能被一台有穷自动机接受。
- 方向二:如果一个语言能被一台有穷自动机接受,那么它一定是正则的。

### 从正则表达式到有穷自动机

我们的任务是:给定任意一个正则表达式,我们都能构造出一台接受它所描述语言的有穷自动机(通常是NFA,因为更方便)。

我们的策略是递归构造。回顾正则表达式的定义:
- **基础情况**:最简单的正则表达式是 $\emptyset$(空语言)和单个符号 $a$。我们可以为每种情况分别构造一个非常简单的 NFA。
- 对于 $\emptyset$,构造一个没有接受状态的自动机。
- 对于 $a$,构造一个只有两个状态的自动机,从初始状态读入 $a$ 转移到接受状态。
- **递归步骤**:更复杂的正则表达式通过并 (Union)、连接 (Concatenation) 和 Kleene 星号 (Kleene Star) 运算组合而成。
- 如果 $L_1$ 和 $L_2$ 都能被自动机接受,则可以构造自动机分别接受 $L_1 \cup L_2$、$L_1 L_2$ 和 $L_1^*$。
- 关键在于证明:有限自动机接受的语言在这三种运算下是**封闭的**。
- **并运算**:通过新建初始状态,使用 **$\varepsilon$-转移**分别连接到两个自动机的初始状态。
- **连接运算**:将第一个自动机的所有**接受状态**通过 **$\varepsilon$-转移**连接到第二个自动机的**初始状态**,并将第二个自动机的接受状态作为整体的接受状态。
- **Kleene 星号**:新建初始状态和接受状态,允许从接受状态通过 $\varepsilon$-转移回到初始状态,同时允许直接接受空串。
- 通过递归应用上述构造方法,可以为**任意正则表达式**构造出一个**等价的 NFA**,从而证明正则表达式描述的语言都能被有限自动机接受。

### 从有穷自动机到正则表达式

现在我们来证明更难的另一个方向:**给定任意一台有限自动机(FA),如何构造出一个等价的正则表达式?**

#### **状态消除法**(State Elimination Method)

我们采用一种叫做**状态消除法**(State Elimination Method)的动态规划思想。其核心步骤如下:

1. 预处理:转换为广义有限自动机 (GFA)

- 首先,将原始自动机改造为**广义有限自动机(GFA)**。GFA 与 NFA 类似,但**转移边上的标记可以是任意正则表达式**,而不仅仅是单个符号。改造标准如下:

- 只有一个唯一的接受状态。
- 没有转移进入初始状态,也没有转移从接受状态出去。

- 通常通过增加新的初始状态和新的接受状态,并用 $\varepsilon$-转移连接它们实现。

2. 状态消除过程

- 逐步消除 GFA 的中间状态。每消除一个状态 $q$,需要修复所有经过它的路径:

- 假设有一条从 $q_i$ 到 $q_j$ 的路径,标记为 $\delta$。
- 还有一条从 $q_i$ 经过 $q$ 到 $q_j$ 的路径,$q_i \to q$ 标记为 $\alpha$,$q \to q_j$ 标记为 $\beta$,且 $q$ 上可能有自环,标记为 $\gamma$。
- 消除 $q$ 后,新增一条直接路径,其正则表达式为 $\alpha \gamma^* \beta$。
- 从 $q_i$ 到 $q_j$ 的新转移标记为原标记和新路径的并集,即 $\delta \cup \alpha \gamma^* \beta$。

- 重复此过程,直到只剩下初始状态和接受状态。

3. 最终结果: 此时,从初始状态到接受状态的**唯一转移边上的**正则表达式,就是与原始自动机等价的正则表达式。

![alt text](image-6.png)


- **初始 GFA**:将原 FA 转换为广义有限自动机(GFA),添加新的起始状态 $q_4$ 和唯一接受状态 $q_5$,并用 $\varepsilon$-转移连接。
- **消除 $q_1$**:移除 $q_1$,将所有经过 $q_1$ 的路径合并。例如,从 $q_4$ 经过 $q_1$ 到 $q_3$ 的路径合并为一条标记为 $a^*b$ 的新边;从 $q_2$ 经过 $q_1$ 到 $q_3$ 的路径合并为 $ba^*b$。
- **消除 $q_2$**:移除 $q_2$,将 $q_3$ 经过 $q_2$ 回到 $q_3$ 的路径与 $q_3$ 的自环合并,得到新的自环 $a \cup ba^*ba^*b$。
- **消除 $q_3$**:移除 $q_3$,将 $q_4$ 到 $q_3$ 的路径、$q_3$ 的自环、以及 $q_3$ 到 $q_5$ 的路径合并,得到从 $q_4$ 到 $q_5$ 的唯一路径。
- **最终正则表达式**:所有中间状态消除后,GFA 只剩下起始和接受状态,两者之间的唯一转移边标记的正则表达式即为原 FA 的等价正则表达式:$\boxed{a^*b(a \cup ba^*ba^*b)^*}$。


#### 数学归纳描述

定义 $R(i, j, k)$ 表示:从状态 $q_i$ 到 $q_j$,且所有中间状态编号不超过 $k$ 的所有路径所对应的字符串集合。

- 基础情况(Base Case, $k=0$):$R(i, j, 0)$ 表示从 $q_i$ 到 $q_j$ 的路径,且**不经过任何中间状态**(编号 $>0$)。这只可能是一步直接转移,因此 $R(i, j, 0)$ 就是所有能直接从 $q_i$ 到 $q_j$ 的符号的集合。如果 $i = j$,还包括空串 $\varepsilon$。这个集合是有限的,可以用正则表达式(如 $a \cup b \cup c$)描述。

- 归纳步骤(Inductive Step):假设对于所有 $i, j$,$R(i, j, k-1)$ 都可以用正则表达式描述。递推公式如下:

$$
R(i, j, k) = R(i, j, k-1) \cup R(i, k, k-1) \left(R(k, k, k-1)\right)^* R(k, j, k-1)
$$

- 公式解释:从 $q_i$ 到 $q_j$,中间状态编号不超过 $k$ 的所有路径分为两类:

1. **不经过 $q_k$ 的路径**:这些路径的中间状态编号都不超过 $k-1$,即 $R(i, j, k-1)$。
2. **经过 $q_k$ 的路径**:可以分解为三部分:
- 从 $q_i$ 到 $q_k$(中间状态不超过 $k-1$):$R(i, k, k-1)$
- 在 $q_k$ 循环任意次(中间状态不超过 $k-1$):$\left(R(k, k, k-1)\right)^*$
- 从 $q_k$ 到 $q_j$(中间状态不超过 $k-1$):$R(k, j, k-1)$

由于正则表达式的三种运算(并、连接、星号)都是封闭的,且归纳假设 $R(\cdot, \cdot, k-1)$ 都是正则的,因此 $R(i, j, k)$ 也必然是正则的。

因此, 正则语言的核心理论结果是,DFA、NFA 和正则表达式在**描述语言的能力**上是完全等价的。

- **NFA 与 DFA 等价**:对于每一台非确定型有限自动机(NFA),都存在一台等价的(接受相同语言的)确定型有限自动机(DFA)。证明方法为“子集构造法”,即将 NFA 的状态集合映射为 DFA 的单个状态。
- 这意味着,NFA带来的所有便利性,都只是“表面上”的。在**计算能力的本质上**,它并没有超越DFA。
- **自动机与正则表达式等价**:一个语言是正则的(即可以用正则表达式表示)当且仅当它被一台有限自动机接受。证明思路包括:
- 从任意正则表达式构造等价的 NFA:为基础情况构造简单自动机,利用自动机在并、连接和 Kleene 星号运算下的封闭性递归组合。
- 从任意有限自动机构造等价的正则表达式:使用状态消除法,逐步移除中间状态并更新转移边的正则表达式,直到只剩下初始和接受状态。

## 正则语言与非正则语言 (Languages that are and are not regular)。

到目前为止,我们已经学习了三种强大的工具来描述和证明一个语言是正则的:

- 为它构造一台有限自动机 (FA) 。
- 为它写出一个正则表达式 。
- 利用正则语言的闭包性质 (Closure Properties),比如并、交、补、连接和克林星号等,从已知的正则语言构造出它 。

**示例1**: 假设字母表 $\Sigma$ 是 $\{0, 1, ..., 9\}$。语言 $L$ 是所有能被 2 和 3 整除的非负整数的十进制表示(并且没有多余的前导零)。请证明 $L$ 是一个正则语言。

第一步:分解问题。我们要证明的语言 $L$ 是“能被 2 整除”的语言 $L_2$ 和“能被 3 整除”的语言 $L_3$ 的交集,即 $L = L_2 \cap L_3$。根据正则语言的闭包性质,只要 $L_2$ 和 $L_3$ 都是正则的,它们的交集 $L$ 也一定是正则的。

第二步:证明 $L_2$ 是正则的。一个数能被 2 整除,等价于它的十进制表示最后一位是 $0, 2, 4, 6, 8$。所有合法的非负整数的十进制表示组成的语言 $L_1$ 可以用正则表达式 $0 \cup [1-9][0-9]^*$ 表示(假设 $\Sigma = \{0,1,\ldots,9\}$)。$L_2$ 就是 $L_1$ 中以偶数结尾的字符串,即 $L_2 = L_1 \cap [0-9]^*[0,2,4,6,8]$。由于 $L_1$ 和 $[0-9]^*[0,2,4,6,8]$ 都是正则语言,交集 $L_2$ 也是正则的。

> $[1-9][0-9]^*$ 这一部分表示所有非零的非负整数。
> - **子部分 B1**:$[1-9]$ 是 $\{1, 2, \dots, 9\}$ 的简写,它由基本正则语言 $\{1\}, \{2\}, \dots, \{9\}$ 通过有限次并集 $\cup$ 得到。由于正则语言对并集运算封闭,$L_{B1} = \{1, 2, \dots, 9\}$ 是正则语言。
> - **子部分 B2**:$[0-9]^*$ 是 $\{0, 1, \dots, 9\}^*$ 的简写,同样是正则语言(通过有限次并集和 Kleene 星号运算)。因此 $L_{B2} = \{0, 1, \dots, 9\}^*$ 也是正则语言。
> - **连接 B1 和 B2**:部分 B 是由 $L_{B1}$(非零数字)和 $L_{B2}$(任意数字串)通过连接运算($L_{B1}L_{B2}$)得到的。由于正则语言对连接运算封闭,$L_B = [1-9][0-9]^*$ 也是正则语言。

第三步:证明 $L_3$ 是正则的。一个数能被 3 整除,当且仅当它的各位数字之和能被 3 整除。我们可以设计一个 3 个状态的 DFA,状态分别表示“数字和模 3 余 0、1、2”。初始状态(也是接受状态)表示余 0。每读入一个数字 $d$,就从当前状态 $q$ 转移到 $((q + d) \bmod 3)$。这台 DFA 能接受所有各位数字和能被 3 整除的字符串,因此 $L_3$ 是正则语言。

第四步:结论。由于 $L_2$ 和 $L_3$ 都是正则语言,且正则语言对交集运算封闭,所以 $L = L_2 \cap L_3$ 也是正则语言。证毕。

我们再来看一个更抽象的例子来巩固闭包性质的应用。

**问题**:假设 $L'$ 是一个已知的正则语言,证明语言 $L = \{xy \mid x \in L',\ y \notin L'\}$ 也是正则的。

**证明**:

首先分析 $L$ 的结构。$L$ 中的字符串由两部分组成:第一部分 $x$ 属于 $L'$,第二部分 $y$ 不属于 $L'$。也就是说,$y$ 来自 $L'$ 的补集 $\overline{L'}$。

因此,$L$ 可以表示为 $L = L' \circ \overline{L'}$,即 $L'$ 与 $\overline{L'}$ 的连接。

根据正则语言的闭包性质:

- 正则语言对补集运算封闭,所以 $\overline{L'}$ 也是正则语言。
- 正则语言对连接运算封闭,所以 $L' \circ \overline{L'}$ 也是正则语言。

综上,$L$ 是正则语言。

下面是一些正则语言的例子:

- $L = \{a^n \mid n \ge 0\}$ 是正则的,因为它的正则表达式就是 $a^*$。
- $L = \{a^n \mid n \text{ is even}\}$ 也是正则的,对应的正则表达式为 $(aa)^*$。
- 如果 $L_0$ 是正则的,那么它的反转语言 $\{w^R \mid w \in L_0\}$ 也是正则的(正则语言对反转运算封闭)。

一个非正则语言的例子:

- $L = \{w \in \{a, b\}^* \mid w \text{ 中 } a \text{ 和 } b \text{ 的数量相等}\}$ 不是正则的。

- 为什么?可以用闭包性质和反证法证明:

- 假设 $L$ 是正则的。我们知道 $a^*b^*$ 是正则语言(正则表达式为 $a^*b^*$)。由于正则语言对交集封闭,$L \cap a^*b^*$ 也应是正则的。但 $L \cap a^*b^*$ 实际上就是 $\{a^n b^n \mid n \ge 0\}$,即所有先若干个 $a$ 再若干个 $b$,且 $a$ 和 $b$ 数量相等的字符串。我们将会证明 $\{a^n b^n \mid n \ge 0\}$ 不是正则语言,这样就产生了矛盾。因此,$L$ 不是正则的。

实际上, 非正则语言数量远大于正则语言. 下面我们从集合了的角度给予分析:

- **问题1:一个非空字母表能组成多少个字符串?**
答案是**可数无穷多**(countably infinite)。因为所有字符串都是有限长度的,可以按长度和字典序一一列举出来。

- **问题2:一个语言是可数的吗?**
是的。任何**语言都是字符串集合的子集**,所以它本身至多是可数无穷的。

- **问题3:一个非空字母表上,总共有多少种可能的语言?**
答案是**不可数无穷多**。因为所有语言的集合,是可数无穷字符串集合的幂集,而**可数集的幂集是不可数**的(其基数与实数集相同)。

- **问题4:有多少种正则语言?**
答案是**可数无穷多**。原因在于,每一个正则语言都可以用一个有限长度的字符串来描述(如正则表达式或有限自动机的描述),而所有有限字符串的集合是可数的。

**结论**:
我们有不可数无穷多种语言,但只有可数无穷多种正则语言。这意味着,绝大多数的语言都是非正则的!


为什么有些语言不是正则的呢?本质原因在于有限自动机(FA)的“有限性”:它只有有限个状态,因此**只能记住有限的信息**。

以 $\{a^n b^n\}$ 为例,判断一个字符串是否属于这个语言,需要机器在读完所有的 $a$ 后,**准确记住 $a$ 的数量**,以便后续与 $b$ 的数量进行匹配。如果 $n$ 可以任意大,这就要求机器拥有**无限的记忆能力或无限个状态**,而有限自动机无法做到这一点。

类似地,像平衡括号这样的语言,也需要无限的计数能力来确保左右括号严格匹配,这超出了有限自动机的能力范围。因此,凡是需要“**无限记忆**”或“**精确计数**”的语言,都不是正则语言。

下面列出了一些经典的、将在本章被证明为非正则的语言:

- $L_1 = \{a^n b^n \mid n \ge 0\}$
- $L_2 = \{a^n \mid n \text{ is prime}\}$
- $L_3 = \{ww^R \mid w \in \{a,b\}^*\}$(回文串)
- $L_4 = \{ww \mid w \in \{a,b\}^*\}$(重复串)

这些语言的共同点在于:它们都要求**对字符串的不同部分进行精确的数量或结构匹配**,而这种匹配超出了有限自动机(FA)**有限内存的能力范围**,因此不是正则语言。

### 泵定理 (Pumping Theorem)

直观的理解很好,但我们需要一个严格的数学工具来证明一个语言不是正则的。这个工具就是大名鼎鼎的**泵定理** (Pumping Theorem)。

一台有穷自动机 $M$ 被定义为一个五元组 $M = (K, \Sigma, \delta, s, F)$。其中,状态集合 $K$ 是一个有穷集合 (a finite set of states)。假设这台 DFA $M$ 拥有的状态总数是 $n$(即 $|K| = n$)。

现在, 我们考虑一个非常长的字符串 $w$,它的长度 $|w|$ 大于或等于状态的总数 $n$。

当 DFA $M$ 从初始状态开始,读取这个长字符串 $w$ 的前 $n$ 个符号时,它会经历 $n$ 步转移,访问 $n+1$ 个状态。

- 鸽巢(Pigeonholes):DFA 拥有的状态总数 $n$。
- 鸽子(Pigeons):DFA 在读取前 $n$ 个符号时,按时间顺序依次访问的 $n+1$ 个状态。
- 初始状态 $q_0$ (第 0 步)
- 第 1 个状态 $q_1$ (第 1 步)
- ...
- 第 $n$ 个状态 $q_n$ (第 $n$ 步)

根据鸽巢原理:如果有 $n+1$ 只鸽子要飞入 $n$ 个鸽巢,那么至少有一个鸽巢里必须有两只或两只以上的鸽子。这意味着:在这 $n+1$ 个被访问的状态序列中,必定有两个状态是同一个状态。

结论:环路的产生假设自动机在第 $i$ 步和第 $j$ 步(其中 $0 \le i < j \le n$)访问了同一个状态 $q$ :$$q_i = q_j = q$$

机器在第 $i$ 步和第 $j$ 步之间读取的那段子字符串,就是导致机器从 $q$ 重新回到 $q$ 的那段路径。这段路径在状态图上表现为一个环路(loop)。

如果 $|w| \ge n$,环路必须发生在字符串前 $n$ 个符号所对应的路径中。这就是泵定理证明的第一步,通过严格的鸽巢原理,证明了对于**足够长的字符串**,**有限自动机**中必然存在一个或多个**环路**。

现在我们就可以把字符串拆分了:
- $x$ 是从开头到 $q_i$ 的部分 ($a_1 \dots a_{i-1}$)。
- $y$ 是从 $q_i$ 绕一圈回到 $q_i$ 的部分 ($a_i \dots a_j$)。
- $z$ 是剩下的部分 ($a_{j+1} \dots a_m$)。

泵定理的正式陈述:如果 L 是一个正则语言,那么必然存在一个整数 n≥1(我们称之为“**泵长度**”),使得任何在 L 中且长度不小于 n 的字符串 w,都可以被**拆分成三段** w=xyz,并且满足以下三个条件:
- $y \ne \epsilon$ (中间的“泵”部分非空)。
- $|xy| \le n$ (循环必定发生在字符串的前 $n$ 个字符以内)。
- 对于所有的 $i \ge 0$,字符串 **$xy^iz$** 仍然属于 $L$ (这就是“泵”的含义:可以泵任意次)。

#### 如何使用泵定理

泵定理是一个破坏性工具。它只能用来**证明一个语言不是正则的**,而不能用来证明一个语言是正则的。证明方法:**反证法** (Proof by contradiction)。

使用泵定理的过程,就像是在玩一个游戏。
- 对手:一个“AI”,它坚信语言 $L$ 是正则的。
- 你:一个“反方辩手”,你的目标是证明AI是错的。

- 游戏规则:
- AI先出招,它给出一个泵长度 $n$。(你不知道 $n$ 是多少,但你知道它存在)。
- 轮到你了,你必须挑选一个非常聪明的字符串 $w \in L$,且 $|w| \ge n$。
- AI再出招,它把你的 $w$ 分解成 $xyz$,但它必须遵守规则($|xy| \le n, y \ne \epsilon$)。它会尽可能地以对它有利的方式来分解。
- 你的最后一击:你必须指出,**无论AI怎么分解**,你总能找到一个 $i$(通常是0或2),使得**泵出的新字符串 $xy^iz$ 不在语言 $L$ 中**。如果你能做到这一点,你就制造了矛盾,证明了AI的观点是错误的,因此 $L$ 不是正则的。

##### 示例: $L=\{a^ib^i \mid i \ge 0\}$ 不是正则的

我们要证明这个语言——所有由一串 $a$ 跟着一串数量完全相等的 $b$ 组成的字符串——不是正则的。严格按照泵定理的反证步骤:

1. **假设**:假设 $L$ 是正则语言。
2. **泵长度**:根据泵定理,存在一个泵长度 $n$。
3. **选择字符串**:取一个长度大于 $n$ 的字符串 $w = a^n b^n$,显然 $w \in L$ 且 $|w| = 2n \ge n$。
4. **拆分规则**:AI 必须将 $w$ 拆分为 $xyz$,满足 $|xy| \le n$ 且 $y \ne \epsilon$。
- 因为 $|xy| \le n$,所以无论怎么拆分, $x$ 和 $y$ 都只包含 $a$,$y = a^i$,其中 $i > 0$。
5. **泵操作**:选择 $i = 0$,得到新字符串 $xz = a^{n-i} b^n$。
6. **矛盾**:如果 $L$ 是正则语言, 那么根据泵定理,得到的新字符串 $xz$ 也是正则语言, 但$xz$ 中 $a$ 的数量为 $n-i < n$,$b$ 的数量为 $n$,两者不相等,因此 $xz \notin L$。
7. **结论**:存在 $i$ 使得 $xy^i z \notin L$,与泵定理矛盾。因此,$L$ 不是正则语言。

##### 证明 $L=\{a^n \mid n \text{ is prime}\}$ 不是正则的

我们采用泵定理进行反证:

1. **假设**:假设 $L$ 是正则语言。
2. **泵长度**:根据泵定理,存在一个泵长度 $n$。
3. **选择字符串**:选择一个大于 $n$ 的素数 $k$,令 $w = a^k$,显然 $w \in L$ 且 $|w| = k \ge n$。
4. **拆分规则**:AI 必须将 $w$ 拆分为 $xyz$,满足 $|xy| \le n$ 且 $y \ne \varepsilon$。由于 $w$ 全由 $a$ 组成,设 $x = a^p$, $y = a^q$, $z = a^r$,其中 $p+q \le n$, $q > 0$, $p+q+r = k$。
5. **泵操作**:根据泵定理,任意 $i \ge 0$,$xy^iz = a^{p + iq + r}$ 应属于 $L$,即 $p + iq + r$ 必须为素数。
6. **构造反例**:令 $i = k + 1$,则新字符串长度为 $p + (k + 1)q + r = (p + q + r) + kq = k + kq = k(q + 1)$。
- $k$ 是素数且 $q \ge 1$,所以 $q + 1 \ge 2$,因此 $k(q + 1)$ 是合数(大于 $k$ 且可分)。
7. **矛盾**:$a^{k(q+1)}$ 不属于 $L$,因为其长度不是素数。与泵定理要求矛盾。

**结论**:存在 $i$ 使得 $xy^iz \notin L$,因此 $L$ 不是正则语言。

### 问题:证明 $L=\{uu^Rv \mid u,v \in \{a,b\}^+\}$ 不是正则的。

这个语言 $L = \{uu^Rv \mid u, v \in \{a, b\}^+\}$ 表示一个非空回文串 $uu^R$ 后面跟着另一个非空串 $v$。直接对 $L$ 使用泵定理较难,因为 $v$ 的存在让结构复杂。我们可以先与一个精心设计的**正则语言**求**交**,得到一个**更简单但同样非正则的语言** $L'$,从而让问题转化为证明 $L'$ 不是正则的。

**第一步:与正则语言求交集**

选择正则语言 $(ab)^+(ba)^+$,与 $L$ 求交得到 $L' = L \cap (ab)^+(ba)^+ = \{(ab)^n(ba)^m \mid m > n \ge 1\}$。其中 $u = (ab)^n$,$u^R = (ba)^n$,$v = (ba)^{m-n}$,要求 $m > n$ 保证 $v$ 非空。

**第二步:对 $L'$ 使用泵定理**

假设 $L'$ 是正则语言。根据泵定理,存在泵长度 $p$。选择字符串 $w = (ab)^p(ba)^{p+1} \in L'$,满足 $|w| \ge p$。

将 $w$ 拆分为 $w = xyz$,其中 $|xy| \le p$,$y \ne \varepsilon$。由于 $|xy| \le p$,$x$ 和 $y$ 都在最前面的 $(ab)^p$ 部分。$y$ 可能是完整的 $(ab)^k$,或是部分片段(如 $a$、$ab$、$b$ 等)。

无论如何拆分 $y$,都可以选择 $i = 0$ 或 $i = 3$,使得泵出后的字符串 $xy^iz$ 不满足 $m > n$,即 $(ab)^{p+q}(ba)^{p+1}$,其中 $q$ 是泵的次数。这样得到的字符串不属于 $L'$,与泵定理矛盾。

**结论**

$L'$ 不是正则语言。由于正则语言的交集仍为正则,而 $L'$ 非正则,因此原语言 $L$ 也不是正则语言。

## 关键研究问题

1. **状态最小化目标**:给定一台 DFA,找到一台接受完全相同语言、且状态数最少的等价 DFA。Myhill-Nerode 定理为最小化提供了理论基础。它定义了一种关于字符串的等价关系 $\approx_L$(如果 $x \approx_L y$,意味着对于任何后缀 $z$,字符串 $xz$ 和 $yz$ 要么都属于 $L$,要么都不属于 $L$)。该定理证明了一个语言是正则的,当且仅当 $\approx_L$ 关系具有有穷个等价类,并且这些等价类的数量,恰好就是接受 $L$ 的最小 DFA 的状态数。最小化算法:首先移除所有从初始状态不可达的状态,然后迭代地识别并合并“等价”的状态。算法开始时,将所有状态分为两个集合:终结状态 $F$ 和非终结状态 $K-F$。在随后的每一步迭代中,检查当前同一集合中的任意两个状态 $p$ 和 $q$。如果存在任何一个输入符号 $a$,使得 $\delta(p, a)$ 和 $\delta(q, a)$ 落在上一轮迭代所划分出的不同集合中,那么 $p$ 和 $q$ 就必须被分离。重复这个细化过程,直到某轮迭代后不再有任何集合被分离为止。此时剩下的集合中的状态都是真正等价的,可以合并为最小自动机的一个状态。

2. **泵定理 (Pumping Lemma) 用途**:这不是用来证明语言是正则的,而是用来证明一个语言不是正则的。定理断言,任何正则语言 $L$ 都存在一个常数 $n$(称为“泵长度”,该值取决于接受它的 DFA 的状态数)。对于 $L$ 中任何长度至少为 $n$ 的字符串 $w$,$w$ 都可以被拆分为三部分 $w=xyz$,且满足以下所有条件:$y \ne \varepsilon$(中间部分非空),$|xy| \le n$(拆分发生在字符串的靠前部分),对于所有的 $i \ge 0$(包括 $i=0$ 时删除 $y$),字符串 $xy^iz$ 必须仍然在 $L$ 中。工作原理:如果一个 DFA 有 $n$ 个状态,它在读取一个长度为 $n$ 或更长的字符串时,根据鸽巢原理,必定至少重复访问了某一个状态。这个状态重复访问路径所对应的字符串就是 $y$。既然这是一条回路,那么这条回路可以被遍历任意多次(或 0 次),机器最终仍会到达相同的接受状态。

3. **证明语言不是正则的方法**:使用泵定理进行反证法证明。步骤如下:
- 假设目标语言 $L$ 是正则的。
- 根据泵定理,必然存在某个泵长度 $n$。
- 选择一个特定的字符串 $w \in L$,要求 $|w| \ge n$。
- 对手可以将 $w$ 拆分为 $w=xyz$,其中 $y \ne \varepsilon$ 且 $|xy| \le n$。
- 证明无论如何拆分 $w$,总能选择一个 $i$ 值(通常是 $i=0$ 或 $i=2$),使得生成的字符串 $xy^iz$ 不在 $L$ 中。
- 这导致了矛盾,因此最初的假设($L$ 是正则的)是错误的。

经典示例:证明 $L = \{a^nb^n : n \ge 0\}$ 不是正则的。选择 $w = a^nb^n$,由于 $|xy| \le n$,$y$ 必须完全由 $a$ 组成(形如 $a^j$ 且 $j>0$)。如果选择 $i=0$,得到的字符串 $xz = a^{n-j}b^n$,a 和 b 的数量不再相等,故 $xz \notin L$,产生矛盾。

On this page
正则语言与有限自动机