字母表与字符串:从拼字游戏到自动机

摘要

文章通过比喻和形式定义介绍了“字母表”(Alphabet)和“字符串”(String)的概念。字母表是一组允许使用的基本符号,如拼字游戏中的字母牌或乐高积木的颜色;字符串则是用这些符号按顺序排列的组合,如拼出的单词或搭建的积木序列。字母表和字符串的关系类似于“砖头池”和“作品”,字母表规定了可用的符号,而字符串是这些符号的有序排列。
在形式语言和自动机中,字母表是自动机和形式语言的基础材料,定义了输入的可能性;字符串则是自动机要检查的对象,形式语言的成员。文章通过具体的自动机例子,如识别“偶数个1”的二进制串和括号匹配的字符串,详细说明了字母表、字符串、自动机的状态和转移过程,并提供了Python代码模拟。最后,文章总结了字母表、字符串、自动机和语言之间的关系,帮助读者更好地理解这些概念在实际中的应用。


一、什么是“字母表”(Alphabet)?

1. 生活比喻

比喻1:拼字游戏的字母牌

  • 想象你在玩拼字游戏(比如Scrabble),桌上有一堆字母牌,比如A、B、C、D。
  • 这些字母牌的集合,就是“字母表”。

比喻2:乐高积木的颜色

  • 你有红、黄、蓝三种颜色的乐高积木。
  • 这三种颜色就是你的“字母表”。
  • 你只能用这三种颜色来搭积木。

2. 形式定义

  • 字母表(通常用希腊字母Σ表示)就是一组允许使用的基本符号
  • 比如:Σ = {a, b},表示只能用a和b。

二、什么是“字符串”(String)?

1. 生活比喻

比喻1:用字母牌拼单词

  • 你用字母牌拼出“CAB”这个单词。
  • 这个“CAB”就是一个“字符串”。
  • 你可以拼出“AB”、“BCA”、“AABBB”等等。

比喻2:用乐高积木搭一条蛇

  • 你用红、黄、蓝积木按顺序搭成“红-蓝-黄-红”。
  • 这就是一个“字符串”:“红蓝黄红”。

2. 形式定义

  • 字符串就是:用字母表里的符号,按顺序排列起来的一串符号
  • 比如:字母表Σ = {a, b},那么“aab”、“bba”、“ababa”都是字符串。

三、字母表与字符串的关系

  • 字母表:就像拼字游戏的“字母池”,规定了你能用哪些“砖头”。
  • 字符串:就是你用这些砖头拼出来的“作品”,每个作品都是砖头的有序排列。

四、在形式语言和自动机中的作用

  • 字母表:自动机和形式语言的“基础材料”,规定了输入的可能性。
  • 字符串:自动机要“检查”的对象,形式语言的“成员”。

比如:

  • 字母表Σ = {0, 1},字符串可以是“0101”、“111”、“0”等。
  • 自动机会检查这些字符串是不是“合法的”(比如是不是偶数个1)。

五、举个具体例子

例子:地铁检票

  • 地铁闸机只认“地铁票”和“公交卡”两种票(字母表Σ = {地铁票, 公交卡})。
  • 你可以用这些票按顺序排队进站,比如“地铁票-公交卡-地铁票”。
  • 这就是一个“字符串”。
  • 闸机(自动机)会检查你这串票是不是符合规则(比如必须先刷地铁票,再刷公交卡)。

六、形象口诀

  • 字母表:拼字的“砖头池”,规定你能用哪些砖头。
  • 字符串:用砖头拼成的“作品”,每个作品都是砖头的有序排列。

我们用一个具体的自动机例子,详细说明字母表、字符串、自动机的状态和转移过程,让你一目了然。


例子:识别“偶数个1”的二进制串

1. 字母表(Alphabet)

  • 记作:Σ = {0, 1}
  • 这表示:我们的“砖头池”只有0和1两种砖头。

2. 字符串(String)

  • 只能用0和1拼成,比如:
    • “0”
    • “1”
    • “1010”
    • “1101”
    • “000”
    • “1111”
    • “”(空串)

3. 语言(Language)

  • 我们要识别的“语言”是:所有1的个数是偶数的字符串
  • 比如:
    • “00” ✔(0个1,偶数)
    • “11” ✔(2个1,偶数)
    • “1010” ✔(2个1,偶数)
    • “1” ✘(1个1,奇数)
    • “1101” ✘(3个1,奇数)

4. 自动机的设计

状态
  • S0:当前读到的1的个数是偶数(初始状态,也是接受状态)
  • S1:当前读到的1的个数是奇数
状态转移规则
  • 在S0:
    • 读到0,留在S0
    • 读到1,转到S1
  • 在S1:
    • 读到0,留在S1
    • 读到1,转到S0
状态转移图
      1
   +-----+      +-----+
   | S0  |----->| S1  |
   +-----+      +-----+
      ^           |
      |           |
      +-----------+
           1

   S0 --0--> S0
   S1 --0--> S1
状态转移表
当前状态输入下一个状态
S00S0
S01S1
S10S1
S11S0
初始状态
  • S0
接受状态
  • S0(因为我们要偶数个1)

5. 检查字符串的过程举例

检查字符串“1010”:
  • 初始在S0
  • 读1:S0 → S1
  • 读0:S1 → S1
  • 读1:S1 → S0
  • 读0:S0 → S0
  • 结束,停在S0(接受)
检查字符串“1101”:
  • 初始在S0
  • 读1:S0 → S1
  • 读1:S1 → S0
  • 读0:S0 → S0
  • 读1:S0 → S1
  • 结束,停在S1(不接受)

6. Python代码模拟

def even_ones(s):
    state = 0  # 0: 偶数个1, 1: 奇数个1
    for c in s:
        if c == '1':
            state = 1 - state
    return state == 0

print(even_ones("1010"))  # True
print(even_ones("1101"))  # False

总结

  • 字母表:Σ = {0, 1}
  • 字符串:如“1010”、“1101”等
  • 自动机:有两个状态,按规则跳转
  • 语言:所有1的个数为偶数的字符串

好的!我们来看一个带栈的自动机(堆栈自动机,PDA),用来识别括号匹配的字符串。这个例子比有限自动机复杂,因为它需要“记住”括号的嵌套情况。


1. 问题描述

字母表:Σ = { (, ) }

语言:所有括号完全匹配的字符串
比如:

  • “”(空串)✔
  • “()” ✔
  • “(())” ✔
  • “()()” ✔
  • “(()())” ✔
  • “())(” ✘
  • “(()” ✘
  • “())” ✘

2. 为什么有限自动机做不到?

有限自动机没有“记忆”,无法记住有多少个左括号还没配对。
堆栈自动机可以用“栈”来记住每一个未配对的左括号。


3. PDA的工作原理

  • 每读到一个“(”,就往栈里压一个符号(比如“X”)。
  • 每读到一个“)”:
    • 如果栈顶有“X”,就弹出一个“X”。
    • 如果栈空,说明多了右括号,不匹配。
  • 读完后,栈必须空,才算完全匹配。

4. 状态转移图(简化版)

我们只需要两个状态:

  • q0:正常处理
  • q_accept:接受状态(读完且栈空)
初始状态q0,栈初始为空

q0 -- 读"(",栈顶任意 --> q0,栈压入"X"
q0 -- 读")",栈顶"X" --> q0,栈弹出"X"
q0 -- 读完,栈顶为空 --> q_accept

图示:

         (,任意
   +------------------+
   |                  v
+------+         +------+
|  q0  | ------> | q0   |
+------+         +------+
   ^                  |
   |                  |
   +------------------+
         ),X
  • 读“(”就压X
  • 读“)”且栈顶是X就弹X
  • 读完且栈空就接受

5. 过程举例

检查字符串 “(()())”

  • 初始:栈空
  • 读“(”:压X → 栈[X]
  • 读“(”:压X → 栈[XX]
  • 读“)”:弹X → 栈[X]
  • 读“(”:压X → 栈[XX]
  • 读“)”:弹X → 栈[X]
  • 读“)”:弹X → 栈[]
  • 读完,栈空,接受!

检查字符串 “(()”

  • 初始:栈空
  • 读“(”:压X → 栈[X]
  • 读“(”:压X → 栈[XX]
  • 读“)”:弹X → 栈[X]
  • 读完,栈非空,不接受!

6. Python代码模拟

def match_parentheses(s):
    stack = []
    for c in s:
        if c == '(':
            stack.append('X')
        elif c == ')':
            if not stack:
                return False
            stack.pop()
    return not stack

print(match_parentheses("(()())"))  # True
print(match_parentheses("(()"))     # False
print(match_parentheses("())("))    # False

7. 总结

  • 字母表:{ (, ) }
  • 字符串:如"(()())"
  • 堆栈自动机:用栈记住未配对的左括号
  • 语言:所有括号完全匹配的字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值