📝 我的笔记

还没有笔记

选中页面文字后点击「高亮」按钮添加

3_丘奇-图灵论题3.1.ZH解释

📜 原文
📖 逐步解释
∑ 公式拆解
💡 数值示例
⚠️ 易错点
📝 总结
🎯 存在目的
🧠 直觉心智模型
💭 直观想象

1\section*{3}
.

丘奇-图灵论题

到目前为止,在我们计算理论的发展中,我们已经提出了几种计算设备模型。有限自动机是具有少量内存的设备的良好模型。下推自动机是具有无限内存但只能以栈的后进先出方式使用的设备的良好模型。我们已经证明,一些非常简单的任务超出了这些模型的能力。因此,它们过于受限,无法作为通用计算机的模型。

📖 [逐步解释]

这部分内容是第三章的引言,起到了承上启下的作用。它首先回顾了之前章节中已经学习过的两种计算模型:有限自动机(Finite Automata, FA)和下推自动机(Pushdown Automata, PDA)。

  1. 回顾已有模型
    • 有限自动机 (FA):它被描述为一个内存非常有限的设备模型。这里的“少量内存”指的是,有限自动机的状态是有限的,它只能通过从一个状态转移到另一个状态来“记住”信息。它没有外部存储器,所以它能记住的信息量严格受限于其状态的数量。这使得它适合模拟一些简单的、对历史信息依赖很小的过程,比如自动售货机、电梯控制器或者识别简单文本模式。
    • 下推自动机 (PDA):它被描述为比有限自动机更强大的模型。它的强大之处在于它拥有一个无限的内存,但这个内存的使用方式是受限的。这个内存是一个(stack),遵循“后进先出”(Last-In, First-Out, LIFO)的原则。你可以把栈想象成一个只能从顶部放入或取出盘子的弹簧碟子架。这种内存结构使得下推自动机能够处理需要“配对”或“计数”的更复杂的语言,比如编程语言中括号的匹配 ( ... ) 或者形如 $a^n b^n$ 的语言(n个a后面跟着n个b)。
  2. 指出已有模型的局限性
    • 文章明确指出,即使是拥有无限内存的下推自动机,也无法完成一些“非常简单的任务”。这里的“简单”是从人类直觉来看的,但在计算理论中有严格的定义。例如,下推自动机无法识别像 $a^n b^n c^n$(n个a,n个b,n个c)这样的语言。这是因为栈的“后进先-出”特性使得它在匹配完b和a之后,就忘记了n的具体值,无法再用它来检查c的数量是否也等于n。
    • 这个局限性引出了一个关键结论:有限自动机下推自动机都“过于受限”,不能作为通用计算机(general-purpose computer)的模型。通用计算机指的是我们日常使用的计算机,它们可以执行任何我们能用算法描述的计算任务(在内存和时间允许的范围内)。
  3. 引出新模型的需求
    • 既然现有的模型不够强大,那么就需要一个更强大的、能够模拟真实计算机计算能力的模型。这为下一节引入图灵机(Turing Machine)埋下了伏笔。丘奇-图灵论题的核心思想就是,任何可以用算法解决的问题,都可以由图灵机来解决。因此,图灵机成为了衡量“可计算性”的黄金标准。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]
  • 有限自动机示例:考虑一个识别以 "1" 结尾的二进制字符串的有限自动机。它只需要两个状态:一个“非1结尾”状态和一个“1结尾”状态。无论输入多长,它只需要这两个状态就能完成任务,因为它只需要记住最后一个字符是什么,这就是“少量内存”的体现。输入 10101,状态变化可能是:q_start -> q_end_with_1 -> q_not_end_with_1 -> q_end_with_1 -> q_not_end_with_1 -> q_end_with_1。最终停在“1结尾”状态,接受该字符串。
  • 下推自动机示例:考虑识别语言 $L = \{0^n 1^n \mid n \ge 0\}$下推自动机。当输入 0011 时:
  1. 读到第一个 0,将一个符号(比如 $`) 压入栈。栈:`$
  2. 读到第二个 0,再压入一个 $. 栈:$$
  3. 读到第一个 1,弹出一个 $`. 栈:`$
  4. 读到第二个 1,再弹出一个 $. 栈:空。
  5. 输入结束,栈为空,接受字符串。

这个过程需要无限内存(栈)来计数 0 的数量,但使用方式是 LIFO。

  • 下推自动机失败的示例:考虑语言 $L = \{0^n 1^n 2^n \mid n \ge 0\}$。当输入 001122 时:
  1. 读到两个 0,压入两个 $。栈:$$
  2. 读到两个 1,弹出两个 $。栈:空。
  3. 现在读到 2,但栈已经空了。机器无法知道 01 的数量(也就是 n 的值,这里是2),因此无法判断 2 的数量是否也与之相等。这就是下推自动机的局限性。
⚠️ [易错点]
  1. 对“无限内存”的误解:学生容易误认为下推自动机的“无限内存”意味着它能做任何事。关键在于“只能以栈的后进先出方式使用”。这个“使用方式”的限制是其能力受限的根本原因。
  2. 混淆“识别”与“计算”:在计算理论的这个阶段,我们主要讨论的是“语言识别问题”,即判断一个给定的字符串是否属于某个语言。这可以看作是一种特殊的计算(输出是“是”或“否”)。引言中提到的“任务”和“模型的能力”都指的是这种识别能力。
  3. “通用计算机”的精确含义:引言中提到的“通用计算机模型”不是指能模拟 Windows 或 macOS 的所有功能,而是指能模拟其核心计算能力,即执行算法的能力。
📝 [总结]

本段是第三章的开篇,通过回顾有限自动机下推自动机这两种计算模型,并指出它们因内存结构或使用方式的限制而无法作为通用计算机的模型,从而引出了寻找一个更强大计算模型的必要性。这个更强大的模型就是图灵机,它将成为本章及后续章节的核心研究对象。

🎯 [存在目的]

本段的目的是为引入图灵机提供动机和上下文。它清晰地定位了新模型在计算能力层级中的位置——它必须比下推自动机更强大,并且强大到足以模拟我们所理解的“计算”的本质。这为后续章节探讨计算的极限(哪些问题是图灵机也无法解决的)奠定了基础。

🧠 [直觉心智模型]
  1. 有限自动机:一个只有短期记忆的人,只能记住几件刚刚发生的事(当前状态)。
  2. 下推自动机:一个记性不好但手边有一叠纸的人。他可以往纸上写东西(压栈),但只能看最上面那张纸,并且看完就得撕掉(弹栈)。他可以记住一长串事情,但必须按相反的顺序回忆。
  3. 通用计算机的需求:我们需要一个既有无限纸张,又可以随时翻阅任何一张纸、并在任何一张纸上做笔记的人。这个人才能模拟真正的思考和计算过程。
💭 [直观想象]

想象一条装配线。

  1. 有限自动机是线上一个简单的传感器,它只能根据当前经过的零件是红色还是蓝色来决定亮绿灯或红灯。它不知道之前经过了多少个红色零件。
  2. 下推自动机是线上一个工人,他面前有一个桶。每经过一个“左括号”零件,他就往桶里放一个球。每经过一个“右括号”零件,他就从桶里拿出一个球。如果最后线上零件走完了,桶也空了,他就知道括号是匹配的。但他不能去数桶底的球,只能操作最上面的。
  3. 现在,我们需要一个更高级的工人,他不仅有一条无限长的传送带(内存),还可以在传送带上自由前后移动,读取任何位置的零件信息,并用笔在零件上做标记或擦掉标记。这个工人就是图灵机,他的能力显然远超前两者。

  1. 对 3.1 图灵机 的介绍

📜 [原文2]

3.1

图灵机

现在我们转向一个更强大的模型,它由艾伦·图灵于1936年首次提出,称为图灵机。与有限自动机类似,但具有无限且不受限制的内存,图灵机是通用计算机的更精确模型。图灵机可以做所有真实计算机能做的事情。尽管如此,即使是图灵机也无法解决某些问题。从非常真实的意义上讲,这些问题超出了计算的理论极限。

图灵机模型使用无限磁带作为其无限内存。它有一个磁头,可以读取和写入符号并在磁带上移动。

最初,磁带只包含输入字符串,其他地方都是空白。如果机器需要存储信息,它可以在磁带上写入这些信息。为了读取它所写入的信息,机器可以将其磁头移回它上面。机器持续计算,直到它决定产生一个输出。通过进入指定的接受状态和拒绝状态来获得接受和拒绝输出。如果它不进入接受状态或拒绝状态,它将永远运行,永不停止。

📖 [逐步解释]

这部分正式引入了图灵机(Turing Machine, TM)的概念,并描述了其基本构成和工作原理。

  1. 图灵机的提出与定位
    • 提出者和时间:由艾伦·图灵在1936年提出,这是一个历史性的里程碑。
    • 核心特性:它被描述为“与有限自动机类似”,这意味着它也有状态和状态转移的概念。但关键区别在于其内存——“无限且不受限制的内存”。这里的“不受限制”是与下推自动机的栈内存相对的,意味着图灵机的内存可以被随机访问。
    • 模型地位图灵机被认为是“通用计算机的更精确模型”,并断言“图灵机可以做所有真实计算机能做的事情”。这正是丘奇-图灵论题的非形式化表述。它暗示了图灵机的计算能力与我们直觉中的“算法”或“机械过程”是等价的。
  2. 图灵机的强大与局限
    • 强大性:它能模拟任何真实计算机。
    • 局限性:即使如此强大的图灵机,也“无法解决某些问题”。这预示了计算理论中一个深刻的结论:存在“不可计算”或“不可判定”的问题。这些问题构成了“计算的理论极限”,是任何计算设备(无论多强大)都无法逾越的鸿沟。
  3. 图灵机的物理模型
    • 无限磁带 (Infinite Tape):这是图灵机的内存。它被想象成一条在两个方向上无限延伸的带子,上面划分成一个个的方格(cell),每个方格可以存储一个符号。这个“无限”是理论上的抽象,保证了计算不会因为内存耗尽而终止。
    • 磁头 (Head):这是一个读写设备。在任意时刻,磁头都指向磁带上的一个方格。它可以做三件事:
  4. 读取 (Read):读取当前方格中的符号。
  5. 写入 (Write):擦除当前方格的符号,并写入一个新符号。
  6. 移动 (Move):向左或向右移动一个方格。
  7. 图灵机的计算过程概述
    • 初始状态:计算开始时,输入字符串被预先放置在磁带上(通常是从最左端开始),磁带的其他部分则充满了特殊的空白符号(blank symbol)。磁头初始时指向输入字符串的第一个符号。
    • 计算步骤:机器根据其当前状态和磁头读取到的符号,依据其内部的规则(转移函数),执行写入和移动操作,并进入下一个状态。
    • 存储与读取:机器可以在磁带的任何位置写入信息(作为“草稿”或“标记”),并通过移动磁头回到那个位置来再次读取它。这种“随机访问”能力是其比下推自动机强大的根本原因。
    • 终止与输出:计算会一直持续,直到机器进入两种特殊的“停机状态”之一:
    • 接受状态 (accept state):如果进入此状态,机器停机并“接受”输入字符串。
    • 拒绝状态 (reject state):如果进入此状态,机器停机并“拒绝”输入字符串。
    • 无限循环 (Looping):如果机器永远不进入接受或拒绝状态,它将“永远运行,永不停止”。这种情况被称为“循环”或“不停机”。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]

假设一台图灵机的任务是将一个二进制数加一。输入为 1011

  1. 初始状态:磁带内容为 ...sqcup 1 0 1 1sqcup ...sqcup 代表空白符号),磁头指向最左边的 1
  2. 工作过程(一个可能的算法)

a. 机器的程序会让磁头一直向右移动,直到找到第一个空白符号,这标志着数字的结束。磁带:... 1 0 1 1 sqcup ...,磁头在 sqcup 上。

b. 然后磁头向左移动一个方格,到达数字的最低位。磁带:... 1 0 1 1 sqcup ...,磁头在最后一个 1 上。

c. 现在开始执行“加一”逻辑:

i. 读到 1,将其改写为 0,然后向左移动。磁带:... 1 0 1 0 sqcup ...,磁头在倒数第二个 1 上。

ii. 又读到 1,将其改写为 0,向左移动。磁带:... 1 0 0 0 sqcup ...,磁头在 0 上。

iii. 读到 0,将其改写为 1,然后停机。磁带:... 1 1 0 0 sqcup ...

d. 机器进入接受状态(表示任务完成)。

这个例子展示了图灵机如何在磁带上移动、读取和写入来完成一个简单的算术运算。它利用磁带存储中间结果(比如进位被隐式地通过状态和磁头移动来处理)。

⚠️ [易错点]
  1. 无限磁带的误解:磁带是“无限可用的”,而不是“已经无限长”。在任何时刻,磁带上只有有限个非空白符号。你可以把它想象成一个普通的磁带,但两端永远用不完,需要时可以自动延长。
  2. 输入与磁带字母表:输入字符串的符号集(输入字母表)通常是磁带上允许出现的符号集(磁带字母表)的子集。磁带字母表还必须包含空白符号,并且可能包含一些用于计算过程中的特殊标记符号。
  3. 停机问题:必须区分“拒绝”和“循环”。“拒绝”是一个明确的、有答案的停机结果,而“循环”则意味着机器永远不会给出答案。这是计算理论中的一个核心难点。
📝 [总结]

本节内容定义了图灵机这一核心计算模型。它由一条无限磁带、一个可移动的读写头和一组有限的状态组成。其关键优势在于其“无限且不受限制”的内存(磁带),允许随机读写。图灵机被认为是通用计算的理论模型,但它也存在能力极限,即存在它无法解决的问题。

🎯 [存在目的]

本段的目的是从概念上建立图灵机的基本图像。它没有深入形式化定义,而是通过与有限自动机的类比和对其物理组件(磁带、磁头)的描述,为读者提供一个直观的、可操作的心理模型。这为后续理解图灵机的具体算法和形式化定义铺平了道路。

🧠 [直觉心智模型]

图灵机就像一个在一条无限长的铁轨上开小火车的工人。

  1. 铁轨:就是磁带,每一段枕木是一个方格。
  2. 枕木上的标记:就是磁带上的符号。
  3. 小火车:就是磁头,它一次只能停在一根枕木上。
  4. 工人的大脑:就是有限状态控制器。
  5. 工人的工作:他看着脚下枕木的标记(读取),然后根据自己大脑中的一本规则书(转移函数)和当前的心情(状态),决定是拿出粉笔在枕木上重画一个标记(写入),然后开着小火车往前一格还是往后一格(移动)。
💭 [直观想象]

想象你在一条无限长的沙滩上。沙滩上已经用贝壳摆出了一行字(输入字符串)。你(磁头)站在第一个贝壳前。你的大脑里有一套指令(状态和转移函数)。

指令可能是:“如果你现在心情是‘寻找末尾’(状态),脚下看到的是一个贝壳(符号),那就继续往右走一步(移动)”。

另一条指令可能是:“如果你心情是‘加一’,脚下看到的是数字‘9’的贝壳,那就把它捡起来,换成一个‘0’的贝壳(写入),然后心情变成‘需要进位’(新状态),并向左走一步(移动)”。

你可以随时在沙滩的任何地方捡起、放下或替换贝壳,也可以在沙滩上自由地来回走动。通过这种方式,你可以执行非常复杂的计算任务。


  1. 图3.1 图灵机示意图与区别总结

📜 [原文3]

图 3.1

图灵机示意图

以下列表总结了有限自动机图灵机之间的区别。

  1. 图灵机既可以在磁带上写入,也可以从磁带上读取。
  2. 读写头可以向左和向右移动。
  3. 磁带是无限的。
  4. 拒绝和接受的特殊状态立即生效。
📖 [逐步解释]

这部分通过一张示意图和四点总结,直观地强化了图灵机有限自动机的核心区别。

  1. 图 3.1 示意图分析
    • FINITE CONTROL (有限控制器):这部分对应图灵机的“大脑”,也就是它的状态集合 $Q$ 和转移函数 $\delta$。它在任何时候都处于某个特定的状态中。图中画了一个 q_i,表示当前状态。
    • TAPE (磁带):这是一条被划分为方格的带子。图中显示了 ... a b a b b a a ... 这样的符号序列,代表磁带上存储的内容。两端的省略号 ... 形象地表示了磁带向两个方向无限延伸。
    • HEAD (磁头):图中用一个箭头指向磁带上的某个方格,表示磁头当前的位置。这个磁头兼具“读”和“写”的功能(Read/Write head)。
  2. 四点区别的详细解释
    • 区别 1: 可读可写 vs. 只读
    • 图灵机:磁头可以在当前方格上写入新的符号,从而改变磁带内容。这使得磁带不仅仅是输入介质,更是可读可写的工作空间(working space)或内存。
    • 有限自动机:其输入磁带是只读的。磁头只能从左到右读取输入,不能修改。
    • 意义:可写能力是图灵机强大的关键。它可以用磁带来存储中间计算结果、做标记、计数等等,极大地扩展了其计算能力。
  • 区别 2: 双向移动 vs. 单向移动
  • 图灵机:磁头可以向左(L)或向右(R)移动。
  • 有限自动机:磁头通常只能从左到右移动一次,读完就结束了。
  • 意义:双向移动意味着图灵机可以反复地扫描和处理输入。它可以先读一遍数据,做些标记,然后回到开头再根据标记进行下一步处理。这种“随机访问”的能力是解决复杂问题的基础。
  • 区别 3: 无限内存 vs. 无内存/有限内存
  • 图灵机:磁带在理论上是无限长的。这意味着计算的唯一限制是算法本身,而不是内存大小。
  • 有限自动机:它没有外部内存。其唯一的“记忆”就是它的当前状态,而状态是有限的。
  • 意义:无限内存消除了因存储空间不足而导致计算失败的可能性,使得图灵机能够处理任意大小的输入和任意复杂的计算(只要该计算是可能的)。
  • 区别 4: 立即停机的特殊状态 vs. 读完输入后判断
  • 图灵机:一旦进入 q_accept(接受状态)或 q_reject(拒绝状态),计算立即停止。无论磁头上还有没有未读的输入。
  • 有限自动机:通常需要读取完整个输入字符串,然后根据其所在的最终状态是否为接受状态来判断。
  • 意义:这种“立即生效”的机制使得图灵机的设计更加灵活。例如,一旦发现输入不符合某种格式,可以立即进入拒绝状态,而无需继续处理剩余的无效部分。这也引入了“停机”和“不停机(循环)”这对核心概念。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]
  • 区别1&2的体现:在一个检查回文串(如 racecar)的图灵机中:
  1. 读最左边的 r,用一个特殊符号 x 替换它(写入)。
  2. 磁头向右移动到最右边,检查是否为 r
  3. 如果是,用 x 替换它(写入)。
  4. 然后磁头向左移动(双向移动),回到最左边的 x 的右边一个位置,重复此过程。

有限自动机无法做到这一点,因为它不能回头,也不能在磁带上做标记。

  • 区别3的体现:如果要计算 $2^{10000}$,这是一个非常大的数。在真实的计算机上可能会耗尽内存。但在图灵机的理论模型中,只要你有足够的时间,磁带总是足够长,可以写下这个数的完整结果。
  • 区别4的体现:一个图灵机用于检查输入是否为质数。输入为 9(以9个 1 表示)。机器可以尝试用 2, 3, 4... 去除它。当它发现 9 可以被 3 整除时,它就立即知道 9 不是质数,于是马上进入 q_reject 状态并停机。它不需要再尝试用 4, 5, 6... 去除。
⚠️ [易错点]
  1. 图灵机与下推自动机的区别:虽然这里只比较了与有限自动机的区别,但与下推自动机的比较也很重要。下推自动机虽然有无限内存(栈),但其访问是受限的(LIFO),并且磁头也是单向只读的。图灵机在内存访问方式(随机访问)和磁头能力(读写、双向)上都远强于下推自动机
  2. “立即生效”的精确含义:这个机制意味着转移函数的结果是最终的。只要 $\delta(q, a) = (q_{accept}, b, L/R)$,无论 $b$$L/R$ 是什么,机器都停机并接受。
📝 [总结]

本段内容通过图示和列表,清晰地阐明了图灵机相较于有限自动机的四大核心优势:可读写、双向移动的磁头,无限的磁带内存,以及立即生效的接受/拒绝状态。这些特性共同构成了图灵机强大计算能力的基础,使其成为一个更通用的计算模型。

🎯 [存在目的]

这部分的存在是为了给读者一个关于图灵机有限自动机能力差异的鲜明、简洁的总结。在介绍了抽象概念之后,这种具体的对比有助于巩固理解,并突出显示了使得图灵机如此特别和强大的关键创新点。

🧠 [直觉心智模型]
  1. 有限自动机:像一个只能向前走的、眼神不好(只能读不能写)的检查员,沿着一条固定的路径检查产品。
  2. 图灵机:像一个可以自由行动的、手持工具箱(可以涂改标记)的工程师。他可以在整个工厂车间(无限磁带)里来回走动,检查、修改任何一个零件(符号),直到他得出最终结论(接受/拒绝)。
💭 [直观想象]

想象你在做一道复杂的数学题。

  1. 有限自动机的方式:你只能从头到尾读一遍题目,然后凭着瞬间记忆直接写下答案。你不能在草稿纸上写任何东西,也不能回头重读题目。这显然只能解决最简单的问题。
  2. 图灵机的方式:你有一张无限大的草稿纸(磁带)。你可以反复阅读题目(磁头来回移动),在草稿纸的任何地方写下中间步骤和公式(写入),然后根据草稿纸上的内容进行下一步推导(读取),直到最终解决问题。这正是一个人解决复杂问题的真实方式。

  1. 对图灵机 M1 的非形式化描述

📜 [原文4]

让我们介绍一个图灵机 $M_{1}$,用于测试语言 $B=\left\{w \# w \mid w \in\{0,1\}^{*}\right\}$ 的成员资格。我们希望 $M_{1}$ 在其输入是 $B$ 的成员时接受,否则拒绝。为了更好地理解 $M_{1}$,想象一下你置身其中,站在由数百万个字符组成的一英里长的输入上。你的目标是确定输入是否是 $B$ 的成员——也就是说,输入是否包含两个由 # 符号分隔的相同字符串。输入太长,你无法记住所有内容,但允许你在输入上前后移动并做标记。显而易见的策略是之字形地移动到 # 两侧的对应位置,并确定它们是否匹配。在磁带上做标记以跟踪哪些位置对应。

我们设计 $M_{1}$ 以这种方式工作。它用读写头在输入字符串上进行多次遍历。每次遍历都会匹配 # 符号两侧的一个字符。为了跟踪已经检查过的符号,$M_{1}$ 会在检查完每个符号后将其划掉。如果它划掉了所有符号,这意味着所有内容都成功匹配,并且 $M_{1}$ 进入接受状态。如果它发现不匹配,它会进入拒绝状态。总而言之,$M_{1}$ 的算法如下。

$M_{1}=$ “在输入字符串 $w$ 上:

  1. 之字形地遍历磁带,在 # 符号两侧的对应位置之间检查这些位置是否包含相同的符号。如果不包含,或者没有找到 #,则拒绝。在检查完符号后将其划掉,以跟踪哪些符号对应。
  2. 当 # 左侧的所有符号都被划掉时,检查 # 右侧是否还有剩余符号。如果还有剩余符号,则拒绝;否则,接受。”
📖 [逐步解释]

这部分通过一个具体的例子——识别语言 $B=\{w\#w\}$,来展示图灵机是如何工作的。它首先用一个生动的比喻来启发思考,然后给出了一个非形式化但清晰的算法描述。

  1. 问题定义
    • 目标语言$B = \{w\#w \mid w \in \{0,1\}^*\}$。这个语言包含所有由一个 # 分隔的、两边完全相同的二进制字符串组成的字符串。例如,011#011 属于 $B$,但 011#01001#01#01 都不属于 $B$
    • 任务:设计一个图灵机 $M_1$,当输入字符串属于 $B$ 时接受,否则拒绝。
  2. 思想启发(比喻)
    • 想象自己是一个站在一条很长很长的写满 01 的纸带(磁带)前的检查员。纸带太长,你记不住全部内容。
    • 你的任务是确认 # 两边的字符串是否一样。
    • 你可以做的是:在纸带上来回走动(移动磁头),并在你看过的字符上打叉(写入/标记)。
    • 最自然的策略(“显而易见的策略”)就是:
  3. $M_1$ 的算法描述

这是对比喻中策略的更正式的算法化描述。

  • 核心思想:通过“之字形”(zig-zag)的移动来回比较 # 两侧的字符,并用“划掉”(crossing off)的方式来标记已比较过的字符。
  • 步骤 1:之字形比较与标记
  • 这是一个循环过程。在每一次循环中,机器:
  1. 找到 # 左边第一个还没被划掉的字符。
  2. 记住这个字符(通过进入不同的状态,比如“刚刚看到了0”状态)。
  3. 用一个特殊符号(比如 x)将其“划掉”(写入)。
  4. 向右移动,越过 #
  5. 找到 # 右边第一个还没被划掉的字符。
  6. 比较这个字符和刚才记住的字符。
    • 如果不匹配,立即进入拒绝状态。
    • 如果匹配,也用 x 将其“划掉”。
  7. 然后磁头移回磁带左端,开始下一次循环。
    • 边界情况处理:在这个过程中,如果根本找不到 #,或者一侧的字符已经用完而另一侧还有(例如 01#010),都会导致不匹配,从而拒绝。
  • 步骤 2:最终检查
  • 当步骤 1 的循环结束时,意味着 # 左边的所有字符都已经被划掉了。
  • 这时需要做最后一次检查:# 右边是否还有没被划掉的字符?
  • 如果(例如输入是 01#010),说明右边的字符串比左边的长,它们不相等,所以拒绝
  • 如果没有(右边也全部被划掉了),说明左右两边长度相同,且对应位置的字符都匹配。所以接受
∑ [公式拆解]
  • $B=\left\{w \# w \mid w \in\{0,1\}^{*}\right\}$
  • $w$:是一个变量,代表一个字符串。
  • $\{0,1\}^*$:表示由 01 组成的任意长度的字符串集合,包括空字符串 ε
  • $w \in \{0,1\}^*$:意味着 $w$ 是一个二进制字符串。例如,$w$ 可以是 0110101ε
  • $w\#w$:表示将字符串 $w$、字符 #、和同一个字符串 $w$ 拼接起来。
  • 示例
  • 如果 $w = `01`,则 $w\#w = 01\#01
  • 如果 $w = `ε` (空字符串),则 $w\#w = \#
  • 如果 $w = `0`,则 $w\#w = 0\#0
  • 语言 B:就是所有形如 $w\#w$ 的字符串的集合。
💡 [数值示例]

让我们用输入 01#01 来模拟 $M_1$ 的算法:

  1. 初始磁带: 01#01
  2. 第一次遍历:

a. 磁头找到第一个 0,记住 0,将其划掉。磁带: x1#01

b. 磁头向右越过 #,找到第一个 0。匹配成功,将其划掉。磁带: x1#x1

c. 磁头回到左端。

  1. 第二次遍历:

a. 磁头找到第一个未划掉的字符 1,记住 1,划掉。磁带: xx#x1

b. 磁头向右越过 #,找到第一个未划掉的字符 1。匹配成功,划掉。磁带: xx#xx

c. 磁头回到左端。

  1. 循环终止:

a. 磁头在左端向右扫描,发现 # 左边没有未划掉的字符了(都是 x)。

  1. 最终检查 (步骤 2):

a. 机器检查 # 右边。发现右边也都是 x,没有剩余的 01

b. 接受

再来看一个失败的例子,输入 01#10

  1. 初始磁带: 01#10
  2. 第一次遍历:

a. 磁头找到第一个 0,记住 0,划掉。磁带: x1#10

b. 磁头向右越过 #,找到第一个 1。发现它与记住的 0 不匹配

c. 立即拒绝。计算停止。

⚠️ [易错点]
  1. 空字符串 w=ε:如果输入是 #,这意味着 $w$ 是空字符串 ε
  2. 算法会怎么做?它在 # 左边找不到 01 来划掉,直接进入步骤 2。
  3. 在步骤 2 中,它检查 # 右边,同样也找不到 01
  4. 因此,它会正确地接受输入 #
  5. 输入不含 #:如果输入是 0101
  6. 算法在步骤 1 中会一直向右扫描寻找 #,直到遇到磁带末尾的空白符号。
  7. 此时,根据“或者没有找到 #,则拒绝”的规则,机器会拒绝
  8. 长度不匹配:如果输入是 0#01
  9. 第一次遍历,00 匹配,磁带变为 x#x1
  10. # 左边已经没有可比较的字符。进入步骤 2。
  11. 检查 # 右边,发现还有一个 1 没有被划掉。
  12. 根据“如果还有剩余符号,则拒绝”的规则,机器拒绝
📝 [总结]

本节通过描述一个用于识别语言 $\{w\#w\}$图灵机 $M_1$ 的算法,生动地展示了图灵机如何利用其可读写、可双向移动的磁头和无限磁带作为工作空间来解决一个比有限自动机下推自动机所能解决的更复杂的问题。该算法的核心是“之字形比较”和“划掉标记”,这是图灵机编程中的常用技巧。

🎯 [存在目的]

这个例子的目的是将图灵机从一个抽象的定义(磁带、磁头)转化为一个解决问题的具体工具。通过一个非形式化的、高层次的算法描述,读者可以直观地理解图灵机的计算过程和其强大功能,而不会立即陷入形式化定义的复杂细节中。这为后面介绍形式化定义和状态图打下了坚实的基础。

🧠 [直觉心智模型]

这就像一个严谨的核对员在核对两份长长的清单。他不会把一份清单全部背下来再去和另一份比较。他会:

  1. 在第一份清单的第一项旁边打个勾✔(划掉)。
  2. 然后翻到第二份清单,找到第一项,比较它们是否一样。一样的话,也在旁边打个勾✔。
  3. 再回到第一份清单,找到第二个没打勾的项目,打勾。
  4. 再翻到第二份清单的第二项,比较,打勾。
  5. ...

直到一份清单全部打完勾。最后,他会快速浏览一下第二份清单,看看是不是也恰好全部打完勾了。如果是,那么两份清单完全一样。这个过程就是 $M_1$ 算法的直觉模型。

💭 [直观想象]

想象有两队士兵(# 两边的字符串)面对面站着。你要确认两队士兵的身高是否一一对应。

你(磁头)走到左边队伍的第一个士兵面前,让他出列(划掉)。然后你走到右边队伍的第一个士兵面前,让他也出列(划掉),但在这之前你比较了他们的身高。如果身高不一样,你立刻宣布“不匹配!”(拒绝)。如果一样,你就回到左边队伍,让第二个士兵出列,再去和右边队伍的第二个士兵比较。

如此往复,直到左边队伍空了。这时你再看一眼右边队伍,如果也空了,那么两队“匹配”(接受)。如果右边还有人站着,说明“不匹配”(拒绝)。


  1. 图3.2 M1计算快照

📜 [原文5]

下图包含 $M_{1}$ 在输入 011000#011000 上启动后磁带的几个不连续的快照。

图 3.2

图灵机 $M_{1}$ 在输入 011000#011000 上计算的快照

📖 [逐步解释]

这部分通过一系列图形化的“快照”(snapshots)来可视化之前描述的 $M_1$ 算法在处理一个具体输入 011000#011000 时的过程。每个快照展示了在某个时间点磁带的内容以及磁头的位置。

  1. 第一个快照 (Top):
    • 磁带内容: 011000#011000
    • 磁头位置: 指向最左边的第一个 0
    • 解释: 这是计算的初始状态。输入字符串被完整地放在磁带上,磁头位于起始位置。
  2. 第二个快照:
    • 磁带内容: x11000#011000
    • 磁头位置: 指向 # 后面的第一个 0
    • 解释: 这显示了第一次比较的过程。机器读取了最左边的 0,将其用 x “划掉”,然后磁头向右移动,越过 #,到达了 # 右边字符串的第一个字符 0,准备进行比较。
  3. 第三个快照:
    • 磁带内容: x11000#x11000
    • 磁头位置: 指向 # 后面的 x
    • 解释: 比较完成。因为 # 左右两边的第一个字符都是 0,匹配成功。所以 # 右边的 0 也被划掉了。现在磁头可能正在向左移动,准备回到磁带的左半部分开始下一轮比较。
  4. 第四个快照:
    • 磁带内容: xx1000#x11000
    • 磁头位置: 指向 # 后面的第一个 1
    • 解释: 这显示了第二次比较的过程。机器在左半部分找到了第一个未被划掉的字符 1(位于第二个位置),将其划掉,然后磁头移动到右半部分,找到了第一个未被划掉的字符 1(也位于第二个位置),准备比较。
  5. 后续快照(未完全展示):
    • 这个过程会继续下去。第三轮会比较并划掉两边的 1。第四轮比较并划掉两边的 0,依此类推。
  6. 最后一个快照 (Bottom):
    • 磁带内容: xxxxxx#xxxxxx
    • 磁头位置: 指向 # 后面的最后一个 x
    • 解释: 这显示了所有比较都成功完成后的状态。# 两边的所有 01 都被 x 替换了。此时,机器会执行算法的第二步:检查 # 两侧是否还有未划掉的字符。它会发现两边都没有了,因此最终会进入接受状态。

这些快照是“不连续的”,意味着它们省略了磁头来回移动的许多中间步骤,只展示了每个“之字形”比较的关键时刻,从而清晰地说明了算法的宏观进展。

∑ [公式拆解]

本段不含公式。

💡 [数值示例]

我们可以用文字更详细地重建两个快照之间的步骤:

  • 从快照2到快照3:
  1. 快照2状态: 磁带 x11000#011000,磁头在 # 后的 0 上。机器内部状态是“要找一个 0 来匹配”。
  2. 比较: 磁头读到 0,与内部状态匹配。
  3. 写入: 机器将 0 改写为 x。磁带变为 x11000#x11000
  4. 移回: 机器进入“返回左端”的系列状态。磁头开始向左移动。... #x11000, ... #x11000, ... 0#x11000, ... 00#x11000, ... 直到磁头碰到磁带最左端的边界。
  5. 准备下一轮: 磁头回到左端后,向右移动,寻找第一个非 x 字符(即 1),准备开始下一轮比较。这个过程的最终结果就是快照4所展示的准备比较第二个字符的状态。
⚠️ [易错点]
  1. 把快照当作连续步骤: 学生可能会误以为机器是一步从快照2跳到快照3的。必须理解中间省略了磁头多次移动和状态转换。快照是关键帧,不是动画的每一帧。
  2. 磁头位置的意义: 每个快照中磁头的位置都非常关键,它揭示了算法当前进行到哪一步。例如,磁头在右半部分意味着正在“寻找匹配”或“刚刚完成匹配”,磁头在左半部分则可能在“寻找下一个要比较的字符”或“返回途中”。
📝 [总结]

图3.2通过一系列磁带快照,直观地演示了图灵机 $M_1$ 在处理输入 011000#011000 时的核心工作流程。它展示了“划掉”和“之字形”比较策略的实际效果,将抽象的算法描述与具体的磁带操作联系起来,加深了读者对图灵机工作方式的理解。

🎯 [存在目的]

这幅图的目的是为了提供一个可视化的辅助教学工具。相比于纯文字描述,图形化的快照能更清晰、更直观地展示算法的动态执行过程,特别是磁带内容随时间的变化。这有助于读者建立一个关于图灵机计算的动态心智模型。

🧠 [直觉心智模型]

这就像观看一部快进的电影,记录一个侦探破解一个密码。

  1. 快照1: 侦探拿到完整的密码纸条。
  2. 快照2: 侦探在纸条的开头做了一个标记,然后跑到纸条的后半部分,准备核对某个字符。
  3. 快照3: 侦探在后半部分也做了一个标记,看起来第一对字符核对成功了。
  4. 快照4: 侦探又在前半部分的第二个字符做了标记,然后又跑到后半部分准备核对第二个字符。
  5. 最后一个快照: 纸条上所有字符都被侦探打上了标记,表示全部核对完毕。

电影省略了侦探来回跑动的过程,只展示了他每次做出关键标记的时刻。

💭 [直观想象]

想象你在用两根手指玩“大家来找茬”的游戏。图片就是磁带。

  1. 初始状态:你的左手手指(磁头)放在左边图片的一个物体上。
  2. 比较过程:你记住这个物体,然后移动你的右手手指(也是磁头的一部分,或者说是由状态记住的“虚拟磁头”)到右边图片上寻找对应的物体。找到后,你用两支笔分别在两个物体上画圈(划掉)。
  3. 快照:就是你每成功找到一对茬,并画上圈之后,拍下的一张照片。这些照片串联起来,就展示了你解决整个找茬游戏的过程。

  1. 对图灵机形式化定义的引言

📜 [原文6]

图灵机 $M_{1}$ 的这种描述草图式地说明了它的功能,但并未提供所有细节。我们可以通过提供类似于为有限自动机下推自动机引入的形式化描述来详细描述图灵机形式化描述指定了图灵机模型形式化定义的每个部分,该模型即将呈现。实际上,我们几乎从不提供图灵机形式化描述,因为它们往往非常庞大。

📖 [逐步解释]

这短短的一段话起到了一个重要的过渡作用,它连接了前面非形式化、高层次的描述和后面严格、数学化的形式化定义。

  1. 承认之前描述的不足
    • 作者明确指出,像刚才对 $M_1$ 的描述(“之字形遍历”、“划掉符号”)是“草图式”(sketchy)的。
    • “草图式”意味着它只勾勒了轮廓,传达了核心思想,但“并未提供所有细节”。例如,它没有明确说明:
    • 机器有多少个状态?每个状态代表什么意义?(比如“正在向右找#”、“记住了一个0”、“正在向左返回”等)
    • 当处于状态 q 并读到符号 a 时,具体应该写入什么符号 b,向哪个方向移动,并进入哪个新状态 r?这些精确的指令都没有给出。
  2. 引入形式化描述的必要性
    • 为了精确无误地定义一台图灵机,我们需要一个形式化描述(formal description)。
    • 这个描述将遵循一个标准的形式化定义(formal definition),就像我们为有限自动机(五元组)和下推自动机(七元组)所做的那样。
    • 形式化描述会把所有细节都交代清楚,不留任何模糊空间,使得机器的行为是完全确定和可分析的。
  3. 预告形式化定义的复杂性
    • 作者在这里打了一个“预防针”:“实际上,我们几乎从不提供图灵机形式化描述,因为它们往往非常庞大。”
    • 这暗示了图灵机的形式化定义(特别是转移函数 $\delta$)会非常复杂和冗长,即使是对于像 $M_1$ 这样看起来相对简单的任务。
    • 这也解释了为什么在计算理论中,我们更倾向于使用更高层次的、类似算法的描述来沟通思想。只要我们确信这种高层次描述可以被转化成一个严格的形式化定义,它就是有效且被接受的。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]

考虑 $M_1$ 的一个细节:当机器读到 # 左边的第一个 0 时发生了什么?

  • 高层次描述:“划掉一个 0 并向右扫描”。
  • 形式化描述需要明确的细节
  1. 假设当前状态是 $q_{start}$,磁头读到 0
  2. 转移函数 $\delta(q_{start}, 0)$ 应该是什么?
  3. 它应该等于一个三元组 $(q_{find\_\#\_after\_0}, x, R)$
    • $q_{find\_\#\_after\_0}$:这是一个新的状态,其“含义”是“我刚刚划掉了一个0,现在正在向右走,目标是找到#”。
    • $x$:这是要写入磁带的新符号,即“划掉”的标记。
    • $R$:表示磁头向右移动。
⚠️ [易错点]
  1. 混淆“形式化定义”和“形式化描述”
  2. 形式化定义 (Formal Definition):是一个通用的模板,规定了一类数学对象(如图灵机)由哪些部分组成(例如,一个七元组)。
  3. 形式化描述 (Formal Description):是使用这个模板来具体定义一个特定的图灵机实例(如 $M_1$)。它会给出七元组中每个部分的具体内容。
  4. 认为高层次描述不严谨:在计算理论中,高层次描述被认为是完全严谨的,前提是存在一个明确的、机械的步骤能将其翻译成形式化描述。这被称为“实现层面的描述”(implementation-level description)。
📝 [总结]

本段作为桥梁,指出了高层次算法描述在思想交流上的便利性和在细节上的缺失。它说明了为了达到数学上的严谨性,我们需要引入图灵机的形式化定义。同时,它也提醒读者,由于形式化描述的极端复杂性,在实践中我们仍将主要依赖更高层次的描述。

🎯 [存在目的]

本段的目的是管理读者的预期。在展示了一个直观易懂的例子后,直接抛出一个复杂的七元组定义可能会让读者感到困惑和不知所措。通过这段话,作者解释了为什么需要这个复杂的定义(为了严谨),以及为什么我们以后会尽量避免使用它(因为它太繁琐),从而让读者平稳地过渡到下一节的数学内容。

🧠 [直觉心智模型]

这就像教人做一道菜。

  1. 高层次描述:“把牛肉切块,和土豆、胡萝卜一起炖。” 这是一个草图,大多数人能明白要做什么。
  2. 形式化描述:一份详细的菜谱,精确到“将牛腩切成3厘米见方的块,土豆去皮切滚刀块,胡萝卜用模具刻成五角星形状。热锅,倒入15毫升食用油,油温七成热时下入牛肉,煎至四面金黄,加入5克姜片、8克葱段...” 这个描述极其详尽,但也很冗长。

作者在这里说的是:“我刚刚告诉了你这道菜大概怎么做,接下来我要给你看一眼真正的详细菜谱长什么样,让你知道它的严谨性。但以后我们聊天,还是会用‘炖牛肉’这种简单的方式来交流。”

💭 [直观想象]

想象你在和一个朋友解释一个宜家家具的组装过程。

  1. 高层次描述:“你先把这四根腿装到这个板子上,就成一个桌子了。”
  2. 形式化描述:就是那本只有图和零件编号、没有任何文字的宜家说明书。它用极其精确但又抽象的符号语言,展示了每一个螺丝应该拧在哪个孔里,每一个零件的朝向。

本段就在说:“我们刚刚用大白话聊了怎么装桌子,现在我带你看看这张官方的、最精确的组装图纸,不过以后我们还是用大白话聊。”


  1. 对图灵机形式化定义的讲解

📜 [原文7]

图灵机的形式化定义

图灵机定义的核心是转移函数 $\delta$,因为它告诉我们机器如何从一个步骤到下一个步骤。对于图灵机$\delta$ 采取以下形式:$Q \times \Gamma \longrightarrow Q \times \Gamma \times\{\mathrm{L}, \mathrm{R}\}$。也就是说,当机器处于某个状态 $q$ 并且磁头位于包含符号 $a$ 的磁带方格上时,如果 $\delta(q, a)=(r, b, \mathrm{~L})$,机器会写入符号 $b$ 替换 $a$,并进入状态 $r$。第三个分量是 L 或 R,表示写入后磁头是向左还是向右移动。在这种情况下,L 表示向左移动。

定义 3.3

图灵机是一个 7 元组 $\left(Q, \Sigma, \Gamma, \delta, q_{0}, q_{\text {accept }}, q_{\text {reject }}\right)$,其中 $Q, \Sigma, \Gamma$ 都是有限集,并且

  1. $Q$ 是状态集,
  2. $\Sigma$ 是不包含空白符号 $\sqcup$ 的输入字母表,
  3. $\Gamma$ 是磁带字母表,其中 $\sqcup \in \Gamma$$\Sigma \subseteq \Gamma$
  4. $\delta: Q \times \Gamma \longrightarrow Q \times \Gamma \times\{\mathrm{L}, \mathrm{R}\}$ 是转移函数,
  5. $q_{0} \in Q$ 是起始状态,
  6. $q_{\text {accept }} \in Q$ 是接受状态,
  7. $q_{\text {reject }} \in Q$ 是拒绝状态,其中 $q_{\text {reject }} \neq q_{\text {accept }}$
📖 [逐步解释]

这部分给出了图灵机的严格数学定义。它首先聚焦于最核心的转移函数 $\delta$,然后给出了完整的七元组定义。

  1. 转移函数 $\delta$ 的讲解
    • 核心地位$\delta$ 被称为定义的核心,因为它包含了图灵机的“程序”或“逻辑”。它规定了机器在任何情况下应该如何行动。
    • 函数签名$\delta: Q \times \Gamma \longrightarrow Q \times \Gamma \times\{\mathrm{L}, \mathrm{R}\}$。这是一个数学函数的标准表示法,我们来逐步拆解它:
    • 输入 (Domain): $Q \times \Gamma$。这是一个笛卡尔积,表示 $\delta$ 函数的输入是一个序对 (状态, 符号)。具体来说,就是 (当前状态, 当前磁头下的符号)
    • 输出 (Codomain): $Q \times \Gamma \times \{\mathrm{L}, \mathrm{R}\}$。这也是一个笛卡尔积,表示 $\delta$ 函数的输出是一个三元组 (新状态, 要写入的符号, 移动方向)
    • 工作实例:文中举例说明:如果 $\delta(q, a) = (r, b, \mathrm{L})$,这意味着:
    • IF: 机器当前状态是 $q$,且磁头读到的符号是 $a$
    • THEN: 机器将执行以下三个动作:
  2. 进入新的状态 $r$
  3. 在当前磁带方格上,擦除 $a$ 并写入 $b$
  4. 将磁头向左(L for Left)移动一个方格。
  5. 定义 3.3:图灵机七元组

这是一个类似于有限自动机(五元组)和下推自动机(七元组)的形式化定义,它精确地描述了一台图灵机需要的所有组件。

  • $M = (Q, \Sigma, \Gamma, \delta, q_0, q_{accept}, q_{reject})$

下面是每个组件的详细解释:

  1. $Q$ (状态集):一个有限的集合,包含了所有可能的状态。例如,在 $M_1$ 的例子里,可能的状态有“寻找#”、“记住了一个0”、“向左返回”等。$Q$ 是有限的,这体现了控制器本身的内存是有限的。
  2. $\Sigma$ (输入字母表):一个有限的集合,包含了可以出现在初始输入字符串中的所有符号。关键点是,它不能包含空白符号 $\sqcup$。这是为了让机器能识别出输入的结束位置。
  3. $\Gamma$ (磁带字母表):一个有限的集合,包含了所有可以出现在磁带上的符号。它必须满足两个条件:
    • $\sqcup \in \Gamma$:空白符号必须是磁带字母表的一部分。
    • $\Sigma \subseteq \Gamma$:输入字母表必须是磁带字母表的子集。这意味着输入字符串中的所有符号都可以在磁带上出现。此外,$\Gamma$ 还可以包含一些额外的、不在 $\Sigma$ 中的符号,比如前面例子中的划掉标记 x
  4. $\delta$ (转移函数):就是前面详细解释过的机器的“程序”,规定了机器的所有行为。
  5. $q_0$ (起始状态)$Q$ 中的一个特殊状态,是机器开始计算时所处的初始状态。
  6. $q_{accept}$ (接受状态)$Q$ 中的一个特殊状态。一旦进入这个状态,机器立即停机并接受输入。
  7. $q_{reject}$ (拒绝状态)$Q$ 中的另一个特殊状态。一旦进入这个状态,机器立即停机并拒绝输入。同时规定 $q_{reject} \neq q_{accept}$,这两个状态必须是不同的。
∑ [公式拆解]
  • $\delta: Q \times \Gamma \longrightarrow Q \times \Gamma \times\{\mathrm{L}, \mathrm{R}\}$
  • $\delta$: 希腊字母 delta,在数学中常用来表示函数或变化。这里是转移函数的名称。
  • $Q$: 状态集。
  • $\Gamma$: 磁带字母表。
  • $\times$: 笛卡尔积符号。$A \times B$ 表示所有形如 $(a, b)$ 的序对的集合,其中 $a \in A, b \in B$
  • $Q \times \Gamma$: 所有(状态,符号)对的集合。
  • $\longrightarrow$: 表示从一个集合到另一个集合的映射,即函数的定义域和陪域。
  • $\{\mathrm{L}, \mathrm{R}\}$: 一个只包含两个元素 L (Left) 和 R (Right) 的集合。
  • $Q \times \Gamma \times \{\mathrm{L}, \mathrm{R}\}$: 所有(新状态,新符号,方向)三元组的集合。
  • 整体含义: $\delta$ 是一个函数,它接受一个(当前状态,当前符号)作为输入,并输出一个(下一个状态,要写入的符号,移动方向)作为结果。
  • $\sqcup$: 一个特殊的符号,代表磁带上的“空白”。通常读作 "blank" 或 "sqcup"。
  • $\Sigma \subseteq \Gamma$: 子集符号。表示集合 $\Sigma$ 中的每一个元素也都存在于集合 $\Gamma$ 中。
💡 [数值示例]

让我们为之前识别 $B=\{w\#w\}$$M_1$ 定义一个部分的形式化描述:

  • $Q = \{q_0, q_{read0}, q_{read1}, q_{find\#}, q_{match0}, q_{match1}, q_{return}, q_{accept}, q_{reject}, ... \}$ (这是一个不完整的状态集)
  • $\Sigma = \{0, 1, \#\}$
  • $\Gamma = \{0, 1, \#, x, \sqcup\}$ (x 是划掉符号)
  • $q_0$: 起始状态
  • $q_{accept}$: 接受状态
  • $q_{reject}$: 拒绝状态
  • $\delta$ 的几个例子:
  • 开始,读到 0: $\delta(q_0, 0) = (q_{find\#}, x, R)$
  • 含义:在起始状态 $q_0$ 读到 0,则进入 $q_{find\#}$ 状态(去找#),把 0 改成 x,然后向右移动。
  • 找 # 的路上,读到 1: $\delta(q_{find\#}, 1) = (q_{find\#}, 1, R)$
  • 含义:如果还在找 # 的状态,读到 1 不用管,保持状态,继续向右。
  • 找到 #: $\delta(q_{find\#}, \#) = (q_{match0}, \#, R)$
  • 含义:如果找到了 #,并且之前是记住了 0(这由 $q_{find\#}$ 状态隐含,更完备的定义需要 $q_{find\#\_after\_0}$ 这样的状态),那么现在进入 $q_{match0}$ 状态(准备匹配0),越过 # 向右走。
  • 匹配 0 成功: $\delta(q_{match0}, 0) = (q_{return}, x, L)$
  • 含义:在准备匹配 0 的状态下,真的读到了 0,匹配成功!进入 $q_{return}$ 状态(准备返回左端),把 0 改成 x,然后开始向左移动。
  • 匹配 0 失败: $\delta(q_{match0}, 1) = (q_{reject}, 1, R)$
  • 含义:在准备匹配 0 的状态下,却读到了 1,不匹配!立即进入拒绝状态。(这里写入 1 和向右移动 R 已经不重要了,因为机器会立即停机)。
⚠️ [易错点]
  1. 状态、符号集都是有限的:尽管磁带是无限的,但图灵机的“程序”(状态 $Q$)和它能理解的“词汇”(字母表 $\Gamma$)都是有限的。这是“机器”的本质。
  2. $\delta$ 是一个全函数吗?:在这个定义中,$\delta$ 的定义域是 $Q \times \Gamma$。在标准的确定性图灵机定义中,通常假定 $\delta$ 对每个输入对都有定义。如果某些组合没有明确的转移,通常隐含地转移到拒绝状态。教科书中也提到,可以把 $q_{accept}$$q_{reject}$$\delta$ 的定义域中去掉,因为机器在这些状态下会停机,不需要转移。
  3. 输入字母表 vs. 磁带字母表:一定要区分 $\Sigma$$\Gamma$$\Sigma$ 是初始给定的,而 $\Gamma$ 是机器在计算中可以使用的所有符号。$\Gamma$ 提供了额外的“草稿”能力。
📝 [总结]

本节给出了图灵机的严格数学定义,即一个七元组 $(Q, \Sigma, \Gamma, \delta, q_0, q_{accept}, q_{reject})$。核心是转移函数 $\delta$,它以当前状态和磁头下的符号为输入,输出新状态、要写入的符号和磁头移动方向。这个形式化定义为后续所有关于图灵机的理论分析提供了坚实的数学基础。

🎯 [存在目的]

本节的目的是提供一个无歧义的、可供数学分析的图灵机模型。虽然高层次描述有助于直觉理解,但只有形式化定义才能让我们能够严格地证明关于计算和语言的定理。这是从计算机科学的直觉层面走向数学理论的必要步骤。

🧠 [直觉心智模型]

这个七元组定义就像是一个机器人的“出厂规格说明书”。

  1. $Q$: 机器人大脑里所有可能的“情绪”列表(有限的)。
  2. $\Sigma$: 机器人出厂时,你能对它说的“初始指令”词汇表。
  3. $\Gamma$: 机器人在它的工作台上能识别和使用的所有“工具和零件”的列表。
  4. $\delta$: 一本厚厚的操作手册,上面写着:“当你的情绪是 A,看到零件 B 时,你应该把情绪切换到 C,用零件 D 换掉 B,然后向左/右走一步。”
  5. $q_0$: 机器人开机时的默认“情绪”。
  6. $q_{accept}$: 机器人完成任务并开心地亮绿灯的“情绪”。
  7. $q_{reject}$: 机器人发现任务失败并沮丧地亮红灯的“情绪”。

这份说明书完整地定义了这个机器人的一切行为。

💭 [直观想象]

想象你在设计一个自动化的棋盘游戏机器人。

  1. $Q$ 是它的所有策略模式:“开局阶段”、“中局攻击”、“残局防守”。
  2. $\Sigma$ 是游戏开始时棋盘上的合法棋子布局。
  3. $\Gamma$ 是棋盘上可能出现的所有东西,包括棋子、以及你为了做计划可能临时放上去的彩色小标记。
  4. $\delta$ 是一本棋谱,告诉你在“中局攻击”模式下,如果你的“车”在 H8 位置,对方的“马”在 G6,那么你应该把“车”移动到 H7,并把策略模式切换到“准备将军”。
  5. $q_0, q_{accept}, q_{reject}$ 分别是“等待开局”、“将死对方,胜利!”和“被将死,失败!”的状态。

这个七元组定义了你的机器人的全部棋艺。


  1. 对图灵机计算过程和格局的讲解

📜 [原文8]

图灵机 $M=\left(Q, \Sigma, \Gamma, \delta, q_{0}, q_{\text {accept }}, q_{\text {reject }}\right)$ 的计算方式如下。最初,$M$ 接收其输入 $w=w_{1} w_{2} \ldots w_{n} \in \Sigma^{*}$ 在磁带最左侧的 $n$ 个方格上,磁带的其余部分是空白的(即,填充了空白符号)。磁头从磁带最左侧的方格开始。请注意,$\Sigma$ 不包含空白符号,因此磁带上出现的第一个空白标志着输入的结束。一旦 $M$ 启动,计算根据转移函数描述的规则进行。如果 $M$ 试图将其磁头向左移出磁带的左端,则即使转移函数指示 L,磁头也会在该次移动中停留在原位。计算继续进行,直到它进入接受状态或拒绝状态,此时它停止。如果两者都没有发生,$M$ 将永远运行。

图灵机计算时,当前状态、当前磁带内容和当前磁头位置都会发生变化。这三个项目的一种设置称为图灵机格局格局通常以特殊的方式表示。对于状态 $q$ 和磁带字母表 $\Gamma$ 上的两个字符串 $u$$v$,我们用 $u q v$ 表示当前状态为 $q$,当前磁带内容为 $u v$,并且当前磁头位置在 $v$ 的第一个符号上的格局。磁带在 $v$ 的最后一个符号之后只包含空白。例如,$1011 q_{7} 01111$ 表示磁带为 101101111,当前状态为 $q_{7}$,并且磁头当前位于第二个 0 上的格局。图 3.4 描绘了一个具有该格局图灵机

图 3.4

具有格局 $1011 q_{7} 01111$图灵机

📖 [逐步解释]

这部分内容详细描述了图灵机从启动到运行的整个过程,并引入了一个极其重要的概念——格局 (configuration),用于精确地捕捉图灵机在任意时刻的“快照”。

  1. 计算的启动与运行
    • 初始设置
    • 输入 $w = w_1w_2...w_n$ 被放置在磁带的最左边。
    • 磁带的其他所有位置都填充着空白符号 $\sqcup$
    • 磁头初始时位于最左边的方格,即 $w_1$ 上。
    • 机器处于起始状态 $q_0$
    • 输入的边界:因为输入字母表 $\Sigma$ 不包含 $\sqcup$,所以从左到右遇到的第一个 $\sqcup$ 就自然地成为了输入字符串的右边界。
    • 计算过程:机器根据转移函数 $\delta$ 的规则一步步进行计算。
    • 左边界处理:这是一个重要的技术细节。如果磁头已经在最左端的方格,而转移函数指令是向左移动 L,那么磁头将停留在原地不动。这提供了一种检测磁带左端的方法。
    • 计算的终结
    • 进入 $q_{accept}$$q_{reject}$,计算停止。
    • 如果永远不进入这两个状态,机器就“永远运行”(循环)。
  2. 格局 (Configuration) 的引入
    • 目的:为了能够形式化地描述图灵机的计算过程,我们需要一种方法来表示机器在任何一个瞬间的完整状态。这个“完整状态”就是格局
    • 格局三要素:一个格局必须包含三个信息:
  3. 当前状态 (current state)
  4. 当前磁带内容 (current tape contents)
  5. 当前磁头位置 (current head location)
    • 格局的表示法:
    • 采用一种紧凑的字符串表示法:u q v
    • q:是当前的状态,属于 $Q$
    • uv:是磁带上从最左端到最后一个非空白字符之间的内容。u 是磁头左边的部分,v 是磁头指向的以及右边的部分。
    • 磁头位置:被约定为 v 的第一个字符。
    • 格局示例详解
    • 格局: 1011 q_7 01111
    • 当前状态: $q_7$
    • 磁带内容: 字符串 101101111 拼接起来,即 101101111。磁带上这部分之外都是空白 sqcup
    • 磁头位置: 指向 01111 的第一个字符,也就是整个磁带上的第五个字符 0
    • 图 3.4 的解读:这幅图直观地展示了格局 1011 q_7 01111 对应的物理状态。有限控制器处于状态 $q_7$,磁带上写着 101101111,并且读写头恰好指在那个 0 上面。
∑ [公式拆解]
  • $w=w_{1} w_{2} \ldots w_{n} \in \Sigma^{*}$
  • $w$: 一个输入字符串。
  • $w_i$: 字符串 $w$ 中的第 $i$ 个字符。
  • $\Sigma^*$: 输入字母表 $\Sigma$ 的克林闭包,表示由 $\Sigma$ 中符号组成的任意有限长度字符串的集合。
  • 格局表示法: $u q v$
  • $u \in \Gamma^*$: 磁头左侧的磁带内容。
  • $q \in Q$: 当前状态。
  • $v \in \Gamma^*$: 从磁头当前位置开始到最后一个非空白字符的磁带内容。
  • 这个表示法巧妙地将三个关键信息(状态、磁带内容、磁头位置)编码到了一个字符串中。
💡 [数值示例]

让我们以一个图灵机为例,其任务是将磁带上第一个 0 改为 1

  • 初始输入: 0110
  • 初始格局: $q_0 0110$
  • 状态: $q_0$
  • 磁带: 0110...
  • 磁头位置: 在第一个 0 上。
  • 假设转移函数: $\delta(q_0, 0) = (q_{accept}, 1, R)$
  • 计算第一步后:
  • 状态变为 $q_{accept}$
  • 磁带 0 被改写为 1
  • 磁头向右移动一格。
  • 新的格局: 1 q_{accept} 110
  • 状态: $q_{accept}$
  • 磁带: 1110...
  • 磁头位置: 在第二个字符 1 上。

因为进入了 $q_{accept}$,机器停机。

另一个例子,左边界处理:

  • 当前格局: $q_2 101$
  • 转移函数: $\delta(q_2, 1) = (q_3, 1, L)$
  • 下一步格局:
  • 机器尝试向左移动,但已经在最左端。所以磁头不动。
  • 状态变为 $q_3$
  • 磁带内容不变(11 覆盖)。
  • 新格局: $q_3 101$
⚠️ [易错点]
  1. 格局字符串的唯一性:对于任何一个图灵机的瞬时状态,其格局表示 u q v 是唯一的(在忽略磁带末尾无限的空白符的前提下)。
  2. 磁带内容 vs. 格局字符串:不要混淆磁带上的内容 uv 和格局 u q v。格局是包含了状态和磁头位置的更丰富的信息。
  3. 空白符在格局中的表示:通常,我们只写出到最后一个非空白字符为止的磁带内容。例如,如果磁带是 01sqcupsqcup...,磁头在 1 上,状态是 q,格局可以写成 0q1,而不是 0q1sqcup。但如果机器在空白符上写入了非空白符,那么格局表示就需要延伸。例如,从 0q1,如果 $\delta(q,1)=(r, \sqcup, R)$,下一步格局是 0sqcup r u_sccup。如果再下一步 $\delta(r, \sqcup) = (s, A, R)$,格局就变成 0sqcup A s u_sccup
📝 [总结]

本节详细定义了图灵机的计算流程,包括初始设置、边界行为和停机条件。最核心的贡献是引入了“格局”这一概念,并给出了其 u q v 的字符串表示法。格局是对图灵机在任意时刻的完整快照,是后续形式化定义“计算步骤”和“接受/拒绝”的基础。

🎯 [存在目的]

引入“格局”概念的目的是为了将图灵机的动态、连续的计算过程,离散化、形式化为一系列静态快照的序列。有了格局,我们就可以用数学语言精确地定义“一步计算”(即从一个格局到下一个格局的转换),从而可以严格地定义整个计算序列、语言的接受和拒绝等概念。这是连接直观理想到数学证明的桥梁。

🧠 [直觉心智模型]

格局就像是棋局中的“局面”。

  1. 一个完整的国际象棋“局面”不仅包括棋盘上所有棋子的位置(磁带内容),还必须包括当前轮到哪一方走棋(当前状态),以及是否存在一些特殊规则如“王车易位”的可能性(也编码在状态里)。
  2. u q v 的表示法就像是一种棋谱记录法,比如 R(N)b2, ...,它用一行文本就记录了整个局面信息。
  3. 图灵机的计算过程,就是从一个初始局面(起始格局)开始,根据规则(转移函数),一步步演变到下一个局面,直到出现“将死”(接受/拒绝格局)或陷入无限循环的局面。
💭 [直观想象]

想象你在玩一个电子游戏。

  1. 格局就是你的游戏存档(save file)。
  2. 这个存档文件必须记录:
  1. 你当前在哪个地图位置,地图上所有怪物和物品的位置(磁带内容)。
  2. 你的角色朝向哪里,甚至你刚刚按下了哪个按钮(磁头位置)。
  3. 你的角色当前的状态是“满血”、“中毒”还是“正在施法”(当前状态)。
    • u q v 就是这个存档文件的一种非常紧凑的文本格式。
    • 玩游戏的过程,就是加载一个存档(起始格局),然后根据游戏规则(转移函数)和你的操作,不断生成新的存档状态(新格局),直到你通关(接受)或角色死亡(拒绝)。

  1. 对“产生”和计算过程的形式化定义

📜 [原文9]

在这里,我们形式化了我们对图灵机计算方式的直观理解。如果图灵机可以在一步内合法地从格局 $C_{1}$ 转移到格局 $C_{2}$,则称格局 $C_{1}$ 产生格局 $C_{2}$。我们通过以下方式正式定义这个概念。

假设我们有 $\Gamma$ 中的 $a, b$$c$,以及 $\Gamma^{*}$ 中的 $u$$v$,以及状态 $q_{i}$$q_{j}$。在这种情况下,$u a q_{i} b v$$u q_{j} a c v$ 是两个格局。如果转移函数 $\delta\left(q_{i}, b\right)=\left(q_{j}, c, \mathrm{~L}\right)$,则称

$$ u a q_{i} b v \quad \text { 产生 } \quad u q_{j} a c v $$

这处理了图灵机向左移动的情况。对于向右移动,如果 $\delta\left(q_{i}, b\right)=\left(q_{j}, c, \mathrm{R}\right)$,则称

$$ u a q_{i} b v \quad \text { 产生 } \quad u a c q_{j} v $$

磁头位于格局的某一端时,会出现特殊情况。对于左端,格局 $q_{i} b v$ 产生 $q_{j} c v$ 如果转移是向左移动的(因为我们阻止机器移出磁带的左端),并且它产生 $c q_{j} v$ 对于向右移动的转移。对于右端,格局 $u a q_{i}$ 等同于 $u a q_{i} \sqcup$,因为我们假设空白跟在格局中表示的磁带部分后面。因此,我们可以像以前一样处理这种情况,磁头不再位于右端。

📖 [逐步解释]

这部分内容使用之前引入的“格局”表示法,来严格定义图灵机的“一步计算”。这个“一步计算”被称为“产生”(yields)。

  1. “产生” (Yields) 的概念
    • “格局 $C_1$ 产生格局 $C_2$” 是 “图灵机在处于 $C_1$ 所描述的瞬时状态时,根据其转移函数 $\delta$,执行一次操作后,进入了 $C_2$ 所描述的瞬时状态” 的形式化说法。
    • 这是对图灵机动态行为的数学建模。
  2. 向左移动 (L) 的形式化定义
    • 前提: 假设转移函数规定 $\delta(q_i, b) = (q_j, c, L)$。这意味着当状态为 $q_i$、读到符号 $b$ 时,应变为状态 $q_j$、写入符号 $c$、并向左移动。
    • 初始格局: $u a q_i b v$
    • 当前状态是 $q_i$
    • 磁头在 $b$ 上。
    • 磁头左边的字符是 $a$
    • 磁带相关部分是 $uabv$
    • 产生的新格局: $u q_j a c v$
    • $b$$c$ 替换,所以磁带现在是 $uacv$
    • 状态从 $q_i$ 变为 $q_j$
    • 磁头向左移动一格,原来在 $b$ 上,现在移动到了 $a$ 上。
    • 在新的格局表示法中,状态 $q_j$ 正好写在了它所指向的字符 $a$ 的左边。这完美地符合了格局的表示规则。
    • 所以,我们说 $u a q_i b v$ 产生 $u q_j a c v$
  3. 向右移动 (R) 的形式化定义
    • 前提: 假设转移函数规定 $\delta(q_i, b) = (q_j, c, R)$。这意味着当状态为 $q_i$、读到符号 $b$ 时,应变为状态 $q_j$、写入符号 $c$、并向右移动。
    • 初始格局: $u a q_i b v$
    • 同上,磁头在 $b$ 上。
    • 产生的新格局: $u a c q_j v$
    • $b$$c$ 替换,磁带变为 $uacv$
    • 状态从 $q_i$ 变为 $q_j$
    • 磁头向右移动一格,原来在 $b$ 上,现在移动到了 $v$ 的第一个字符上(如果 $v$ 不为空)。
    • 在新的格局表示法中,状态 $q_j$ 正好写在了它所指向的 $v$ 的左边,而 $b$ 被替换后的 $c$ 归入了左边部分,成为 $uac$。这也完美符合格局表示规则。
    • 所以,我们说 $u a q_i b v$ 产生 $u a c q_j v$
  4. 边界情况 (Special Cases)
    • 左端 (Left End)
    • 初始格局: $q_i b v$ (磁头在最左边的字符 $b$ 上)。
    • 向左移动: 如果 $\delta(q_i, b) = (q_j, c, L)$,因为磁头不能移出左边界,它会停在原地。新格局是 $q_j c v$。状态变为 $q_j$bc覆盖,磁头仍然在最左边(新c)上。
    • 向右移动: 如果 $\delta(q_i, b) = (q_j, c, R)$,新格局是 $c q_j v$bc覆盖,磁头移到右边v的第一个字符上。
    • 右端 (Right End)
    • 初始格局: $u a q_i$。这被视为等同于 $u a q_i \sqcup$
    • 假设 $\delta(q_i, \sqcup) = (q_j, c, R)$
    • 初始格局等效于 $u a q_i \sqcup$。根据右移规则,产生的新格局是 $u a c q_j \sqcup$ (因为 $v$ 是空串)。这可以简写为 $u a c q_j$
    • 这说明图灵机可以在磁带的空白区域上写入,从而扩展其工作空间。
∑ [公式拆解]

$$ u a q_{i} b v \quad \text { 产生 } \quad u q_{j} a c v $$

  • 解释: 这是一个形式化的“产生”关系,基于向左移动的转移 $\delta(q_i, b) = (q_j, c, L)$
  • 左侧 $u a q_i b v$:
  • q_ib前,表示磁头指向b
  • ab左边的字符。
  • 右侧 $u q_j a c v$:
  • bc覆盖。
  • 状态变为q_j
  • 磁头向左移动,指向a,所以q_j写在a的前面。

$$ u a q_{i} b v \quad \text { 产生 } \quad u a c q_{j} v $$

  • 解释: 这是一个形式化的“产生”关系,基于向右移动的转移 $\delta(q_i, b) = (q_j, c, R)$
  • 左侧 $u a q_i b v$:
  • 同上,磁头指向b
  • 右侧 $u a c q_j v$:
  • bc覆盖,并成为左边部分u的延伸,变成uac
  • 状态变为q_j
  • 磁头向右移动,指向v的第一个字符,所以q_j写在v的前面。
💡 [数值示例]

假设 $\delta(q_3, 0) = (q_5, x, L)$$\delta(q_3, 1) = (q_4, y, R)$

  1. 左移示例:
    • 初始格局: 11 q_3 01 (磁头在 0 上)
    • u=1, a=1, q_i=q_3, b=0, v=1
    • 应用 $\delta(q_3, 0) = (q_5, x, L)$,其中 $q_j=q_5, c=x$
    • 产生的格局是 $u q_j a c v = 1 q_5 1 x 1$
    • 新格局: 1 q_5 1x1 (状态 $q_5$,磁头在 1 上,磁带 11x1)
  2. 右移示例:
    • 初始格局: 11 q_3 10 (磁头在 1 上)
    • u=1, a=1, q_i=q_3, b=1, v=0
    • 应用 $\delta(q_3, 1) = (q_4, y, R)$,其中 $q_j=q_4, c=y$
    • 产生的格局是 $u a c q_j v = 11y q_4 0$
    • 新格局: 11y q_4 0 (状态 $q_4$,磁头在 0 上,磁带 11y0)
  3. 左边界示例:
    • 初始格局: q_3 10 (磁头在最左边的 1 上)
    • 应用 $\delta(q_3, 1) = (q_4, y, L)$ (假设有此规则)。
    • 因为无法左移,磁头不动。
    • 新格局: q_4 y0 (状态 $q_4$,磁头在 y 上,磁带 y0)
⚠️ [易错点]
  1. 格局字符串的操作: 学生需要熟练掌握 uqv 这种表示法。关键是记住状态 q 左边的字符串 u 是磁头严格左边的部分,而 q 右边的字符串 v 的第一个字符就是磁头指向的字符。
  2. uv 可以是空串:
  3. 如果磁头在最左端,$u$ 是空串,格局为 $q_i b v$
  4. 如果磁头指向最后一个非空字符,$v$ 就是单个字符,其后是空串。格局为 $u a q_i b$
  5. 右端扩展: 必须理解在磁带的“末尾”(最后一个非空字符)之后全是空白符 sqcup,并且机器可以在这些空白符上写入,从而使写有非空字符的磁带部分变长。
📝 [总结]

本节为图灵机的“一步计算”提供了严格的形式化定义,即“产生”(yields)关系。通过对格局字符串的操作,它精确地描述了在左移、右移和边界情况下,一个格局如何转换为下一个格局。这是分析图灵机计算过程的关键数学工具。

🎯 [存在目的]

本节的目的是将图리기的计算过程从一个动态的、物理的想象(磁头移动、写入)转化为一个纯粹的、符号化的数学操作(一个字符串如何根据规则变为另一个字符串)。这种转化使得我们可以用序列、集合等数学工具来分析计算,是所有可计算性理论证明的基础。

🧠 [直觉心智模型]

这就像在定义象棋的“一步棋”如何改变棋盘“局面”。

  1. 局面: 格局 $C_1$
  2. 棋规: 转移函数 $\delta$。例如,“马走日”。
  3. 走一步棋: “产生”的过程。
  4. 新局面: 格局 $C_2$

本节内容就是用一种精确的语言,去描述“如果当前局面是 A,根据规则 B,那么下一步的局面必然是 C”。例如,形式化地定义“马从 g1 跳到 f3”是如何改变棋盘表示字符串的。

💭 [直观想象]

想象你在用一个文本编辑器编辑一行文字,光标就是磁头。

  1. 格局 ua q_i bv: 文本内容是 uabv,光标 | 位于 b 的前面,即 ua|bvq_i 是你当前的心情。
  2. 左移规则 $\delta(q_i, b)=(q_j, c, L)$:
  3. 你的心情变为 $q_j$
  4. 你按了一下 delete 键删除 b,然后输入 c。文本变为 uacv
  5. 你按了一下左方向键 <-。光标移动到 a 的前面。
  6. 最后的状态是:心情 $q_j$,文本 uacv,光标 u|acv。这对应的格局就是 u q_j acv
  7. 右移规则 $\delta(q_i, b)=(q_j, c, R)$:
  8. 类似地,你删除 b,输入 c
  9. 你按了一下右方向键 ->。光标移动到 v 的第一个字符前面。
  10. 最后的状态是:心情 $q_j$,文本 uacv,光标 uac|v。这对应的格局就是 uac q_j v

  1. 对语言接受、图灵可识别、图灵可判定的定义

📜 [原文10]

$M$ 在输入 $w$ 上的起始格局格局 $q_{0} w$,表示机器处于起始状态 $q_{0}$,其磁头位于磁带最左侧的位置。在接受格局中,格局的状态是 $q_{\text {accept }}$。在拒绝格局中,格局的状态是 $q_{\text {reject }}$接受格局拒绝格局停机格局,不再产生进一步的格局。因为机器被定义为在 $q_{\text {accept }}$$q_{\text {reject }}$ 状态时停机,所以我们也可以等效地将转移函数定义为更复杂的形式 $\delta: Q^{\prime} \times \Gamma \longrightarrow Q \times \Gamma \times\{\mathrm{L}, \mathrm{R}\}$,其中 $Q^{\prime}$$Q$ 不包含 $q_{\text {accept }}$$q_{\text {reject }}$。如果存在一系列格局 $C_{1}, C_{2}, \ldots, C_{k}$,则图灵机 $M$ 接受输入 $w$,其中

  1. $C_{1}$$M$ 在输入 $w$ 上的起始格局
  2. 每个 $C_{i}$ 产生 $C_{i+1}$,并且
  3. $C_{k}$ 是一个接受格局

$M$ 接受的字符串集合是语言 $M$,或由 $M$ 识别的语言,表示为 $L(M)$

定义 3.5<br>如果某个图灵机识别一种语言,则称该语言是图灵可识别的${ }^{1}$

当我们启动图灵机处理输入时,可能会出现三种结果。机器可能接受、拒绝或循环。循环是指机器根本不停止。循环可能涉及任何简单或复杂的行为,但永不导致停机状态。

图灵机 $M$ 可能通过进入 $q_{\text {reject }}$ 状态并拒绝,或者通过循环来拒绝接受输入。有时很难区分一个正在循环的机器和一个仅仅运行了很长时间的机器。因此,我们更喜欢在所有输入上都停止的图灵机;此类机器永不循环。这些机器称为判决机,因为它们总是做出接受或拒绝的决定。识别某种语言的判决机也被称为判决该语言。

定义 3.6

如果某个图灵机能判定一种语言,则称该语言是图灵可判定的,或简称为可判定的。 ${ }^{2}$

📖 [逐步解释]

这部分内容基于“格局”和“产生”的概念,正式定义了什么叫“图灵机接受一个字符串”,并引出了两个核心的语言类别:图灵可识别语言图灵可判定语言

  1. 特殊格局的定义
    • 起始格局 (Start Configuration): 对于输入字符串 w,起始格局固定为 q_0 w。这精确地描述了计算开始的瞬间。
    • 接受格局 (Accepting Configuration): 任何状态为 q_accept 的格局。
    • 拒绝格局 (Rejecting Configuration): 任何状态为 q_reject 的格局。
    • 停机格局 (Halting Configuration): 接受格局和拒绝格局统称为停机格局。它们是计算的终点,不会再“产生”任何新的格局。
    • 关于 $\delta$ 的补充说明: 因为停机格局是终点,所以转移函数 $\delta$ 对于 q_acceptq_reject 状态的输入是无关紧要的。因此,可以认为 $\delta$ 的定义域实际上是 $(Q - \{q_{accept}, q_{reject}\}) \times \Gamma$
  2. “接受”一个输入的定义
    • 图灵机 $M$ 接受输入 $w$ 的条件是:存在一个有限的格局序列 $C_1, C_2, ..., C_k$
    • 这个序列必须满足三个条件:
  3. $C_1$ 必须是起始格局 $q_0 w$
  4. 序列中任意相邻的两个格局 $C_i$$C_{i+1}$,必须满足 $C_i$ 产生 $C_{i+1}$。这表示这是一个合法的计算步骤序列。
  5. 最后一个格局 $C_k$ 必须是一个接受格局。
    • 语言 L(M): 由图灵机 $M$ 接受的所有字符串 w 构成的集合,被称为 $M$ 的语言,记作 $L(M)$
  6. 图灵可识别语言 (Turing-recognizable Language)
    • 定义 3.5: 如果一个语言 $L$ 是某个图灵机 $M$ 的语言(即 $L = L(M)$),那么 $L$ 就被称为图灵可识别的
    • 这类语言有时也被称为“递归可枚举语言”(recursively enumerable language)。
  7. 计算的三种可能结果
    • 当一台图灵机 $M$ 在输入 w 上运行时,有且只有三种可能性:
  8. 接受 (Accept): $M$ 进入 $q_{accept}$ 并停机。
  9. 拒绝 (Reject): $M$ 进入 $q_{reject}$ 并停机。
  10. 循环 (Loop): $M$ 永不进入 $q_{accept}$$q_{reject}$,计算永不停止。
    • 重要的区分: 对于一个输入 w,如果它不被接受,有两种可能:要么被明确拒绝,要么机器陷入循环。
  11. 图灵可判定语言 (Turing-decidable Language)
    • 动机: “循环”是一个不确定的状态。我们无法知道机器是正在进行一个超长时间的计算,还是已经陷入了死循环。这种不确定性在很多实际应用中是不可接受的。因此,我们更偏爱那些“从不循环”的图灵机
    • 判决机 (Decider): 一个在任何输入上都能保证停机(无论是接受还是拒绝)的图灵机被称为判决机
    • 判决 (Decides): 如果一个判决机识别一个语言,我们就说它“判决”这个语言。
    • 定义 3.6: 如果一个语言 $L$ 可以被某个判决机 $M$ 所判决,那么 $L$ 就被称为图灵可判定的,或简称可判定的 (decidable)。
    • 这类语言有时也被称为“递归语言”(recursive language)。
  12. 两个类别的关系
    • 从定义可以看出,任何一个可判定的语言,必然是图灵可识别的。(因为判决机也是一台图灵机)。
    • 反过来不一定成立。文章预告了,后面会证明存在图灵可识别不可判定的语言。这是计算理论中一个非常深刻和重要的结果。
∑ [公式拆解]

本段不含显著的数学公式,主要是定义。

💡 [数值示例]
  • 可识别 vs. 可判定:
  • 语言 A: $L_A = \{w\#w \mid w \in \{0,1\}^*\}$。我们之前描述的 $M_1$ 算法,对于任何输入,它都会在有限步内划掉所有字符并检查,最终停在接受或拒绝状态。所以 $M_1$ 是一个判决机。因此,语言 $L_A$可判定的
  • 语言 H (停机问题,将在后续章节学到): 考虑一个语言 $L_H$,它包含了所有“会停机的程序”的描述。我们可以设计一个图灵机 $M_H$ 来“识别”它:$M_H$ 拿到一个程序描述,就在自己的磁带上模拟运行这个程序。如果模拟的程序停机了,$M_H$ 就进入接受状态。
  • 问题: 如果模拟的程序本身陷入了死循环怎么办?那么 $M_H$ 也会跟着陷入死循环!
  • 结论: $M_H$ 不是一个判决机,因为它在某些输入上会循环。但它确实能识别 $L_H$(因为任何会停机的程序,最终都会被它模拟成功并接受)。因此,$L_H$图灵可识别的。事实证明 (后面会学到),不存在任何判决机可以判决 $L_H$,所以 $L_H$不可判定的
⚠️ [易错点]
  1. 识别和判定的核心区别:
  2. 识别 (Recognize): 对于属于语言的字符串,保证停机并接受。对于不属于语言的字符串,可能停机并拒绝,也可能永不婷姬
  3. 判定 (Decide): 对于任何字符串(无论是否属于语言),都保证在有限时间内停机,并给出明确的接受拒绝的答案。
  4. "拒绝" vs. "不接受": 这是一个微妙但重要的区别。
  5. "不接受"一个字符串,可以是因为机器停机拒绝了它,也可以是因为机器在它上面循环了。
  6. "拒绝"一个字符串,特指机器进入 $q_{reject}$ 状态并停机。
  7. 所有可判定语言都是图灵可识别的: 这个结论是直接从定义得出的。如果一个语言是可判定的,那么存在一个判决机 $M$ 来判决它。这个判决机 $M$ 本身就是一台图灵机,它识别这个语言。所以这个语言也是图灵可识别的。
📝 [总结]

本节内容在形式化了图灵机的单步计算后,进一步定义了完整的计算过程和结果。它定义了“接受”一个字符串的严格条件,并在此基础上,定义了计算机科学中两个最重要的语言类别:图灵可识别语言(允许对不属于语言的输入循环)和图灵可判定语言(要求对所有输入都必须停机)。判决机作为一种“行为良好”的图灵机被特别强调。

🎯 [存在目的]

这部分的目的是建立计算复杂性理论的基石。通过区分“可识别”和“可判定”,我们开始对问题的“难度”进行分级。

  1. 可判定问题:是我们最希望遇到的“好问题”,因为总有算法能给出“是”或“否”的答案。
  2. 可识别但不可判定的问题:是一类更“坏”的问题。我们或许能验证“是”的答案,但对于“否”的答案,我们可能永远等不到结果。

这种分类对于理解计算的本质和极限至关重要。

🧠 [直觉心智模型]

想象你在做一名法官。

  1. 图灵可识别的法官: 对于有罪的被告(属于语言的字符串),他总能经过审理,最终宣判“有罪”(接受)。但对于无辜的被告(不属于语言的字符串),他可能会宣判“无罪”(拒绝),也可能把案子无限期地拖延下去,永远不审结(循环)。
  2. 图灵可判定的法官 (判决机): 这是一位模范法官。对于任何被告,无论有罪无罪,他都保证在有限时间内审结,并给出“有罪”或“无罪”的明确判决。他从不拖延。
💭 [直观想象]

你在寻找传说中的“黄金城”。

  1. 可识别的策略: 你有一个地图,上面标明了所有可能的路径。你沿着一条路走,如果走到了黄金城,你就成功了(接受)。但有些路可能是无尽的迷宫(循环),你一旦走进去就永远出不来。你无法确定一条你正在走的路究竟是通向死胡同(拒绝)还是无尽的迷宫(循环)。
  2. 可判定的策略: 你有一台神奇的GPS。你输入“黄金城”,它会对世界上每一寸土地进行分析,并最终在屏幕上显示“存在,坐标XXX”或“不存在”。它保证会给你一个答案,从不卡死。

  1. 图灵机示例的引言

📜 [原文11]

图灵机示例

就像我们对有限自动机下推自动机所做的那样,我们可以通过指定其七个部分来形式化描述一个特定的图灵机。然而,除了微小的图灵机之外,达到这种详细程度可能会很麻烦。因此,我们不会花太多时间提供此类描述。我们主要

[^0]只提供更高级别的描述,因为它们对我们的目的来说足够精确,并且更容易理解。然而,重要的是要记住,每个更高级别的描述实际上都只是其形式化对应物的简写。只要有耐心和细心,我们就可以详细地形式化描述本书中的任何图灵机

为了帮助您理解形式化描述高级描述之间的联系,我们在接下来的两个示例中给出状态图。如果您已经对这种联系感到满意,可以跳过它们。

📖 [逐步解释]

这部分是接下来几个具体示例的引言,旨在说明描述图灵机的不同层次,并解释为什么本书主要采用高层次描述。

  1. 回顾描述方法:
    • 作者提到,我们可以像之前学习有限自动机下推自动机一样,通过完整列出七元组的每一个组件来给出一个图灵机形式化描述。这是最底层、最精确的描述方法。
  2. 形式化描述的缺点:
    • 麻烦 (tedious)庞大 (very large): 作者再次强调,对于几乎所有非平凡的图灵机,写出完整的七元组(特别是转移函数 $\delta$ 的所有规则)是一项极其繁琐和冗长的工作。
  3. 本书采用的策略:
    • 主要使用高层次描述 (higher-level descriptions): 这指的是类似之前对 $M_1$ 的算法描述(“之字形遍历”、“划掉”等)。这种描述更接近伪代码,关注算法逻辑而非状态转移的细节。
    • 原因: 高层次描述“足够精确”并且“更容易理解”。它能清晰地传达解决问题的思路,而不会让读者淹没在海量的状态和转移规则中。
  4. 重要提醒:
    • 高层次描述是简写: 必须牢记,任何一个高层次描述都只是其背后那个庞大的形式化描述的一个“简写”或“别名”。
    • 可转化性: 理论上,只要有足够的时间和耐心,任何一个清晰的高层次描述都可以被“编译”或“翻译”成一个完整的、严格的形式化七元组描述。这个可转化性保证了高层次描述的严谨性。
  5. 接下来示例的目的:
    • 为了帮助读者建立高层次描述状态图形式化描述这三者之间的联系,接下来的两个例子(示例 3.7 和 3.9)会提供状态图 (state diagram)
    • 状态图是一种中间层次的描述,它比算法描述更具体(显示了状态和转移),但比完整的 $\delta$ 函数列表更直观。
    • 作者也贴心地提示,如果读者已经理解了这三者之间的关系,可以跳过这两个详细的例子。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]

描述层次的类比:

  • 高层次描述: “写一个程序,对一个数字列表进行排序。”
  • 中间层次描述 (状态图/伪代码):

```

for i from 0 to n-1:

for j from i+1 to n:

if list[i] > list[j]:

swap(list[i], list[j])

```

  • 形式化描述 (七元组/机器码): 一长串二进制的机器指令,或者一个包含了数百条规则的图灵机转移函数 $\delta$ 表。

显然,对于人类沟通而言,高层次描述是最高效的。

⚠️ [易错点]
  1. 轻视高层次描述的严谨性: 学生可能会因为高层次描述看起来像普通英语而认为它不“数学”或不“严谨”。关键在于理解其背后有严格的形式化基础作为支撑。只要描述清晰无歧义,它在计算理论中就是被完全接受的。
  2. 认为所有图灵机都能画出简洁的状态图: 只有状态和转移规则相对较少的图灵机才能被清晰地绘制成状态图。对于复杂的图灵机,状态图会变成一团乱麻,失去其直观性。
📝 [总结]

本段作为示例部分的开场白,阐述了描述图灵机的三种层次:高层次算法描述、中间层次的状态图和底层的形式化描述。作者明确表示,为了清晰和简洁,将主要采用高层次描述,并强调这种描述的严谨性来源于其可被翻译为形式化描述。接下来的示例旨在通过状态图来展示这种联系。

🎯 [存在目的]

本段的目的是进行“教学法”上的说明。它向读者解释了作者为什么选择某种特定的方式来呈现内容,并管理读者对后续示例复杂度的预期。这有助于学习者更好地理解不同描述方式的角色和优缺点,从而更有效地掌握图灵机的设计思想。

🧠 [直觉心智模型]

这就像学习编程语言。

  1. 高层次描述: 老师用自然语言讲解“快速排序”的思想:选一个基准值,把小的放左边,大的放右边,然后递归处理。
  2. 状态图/伪代码: 老师在黑板上写下 quicksort(array, low, high) 的伪代码。
  3. 形式化描述: 老师展示该伪代码编译后的汇编代码或机器码。

通常我们学习算法时,最关注的是第一层和第二层。第三层是确保计算机能够精确执行的基础,但我们很少直接去读写它。

💭 [直观想象]

你在教一个机器人画画。

  1. 高层次描述: “画一个‘蒙娜丽莎’。”
  2. 中间层次描述 (状态图): 一系列指令,如“切换到7号画笔”,“蘸取棕色颜料”,“从坐标(x1, y1)到(x2, y2)画一条曲线”...
  3. 形式化描述 (七元组): 控制机器人手臂每个马达旋转角度和力度的底层电子信号序列。

本段在说:“我主要会用‘画一个蒙娜丽莎的微笑’这种方式来下指令,因为这最容易懂。但我会先给你看两个例子,让你明白这背后其实对应着非常精密的画笔和颜料操作,而这些操作又对应着更底层的马达控制信号。”


  1. 示例 3.7: 判定语言 A={0^(2^n)}

📜 [原文12]

示例 3.7

在这里,我们描述一个图灵机 (TM) $M_{2}$,它判定语言 $A=\left\{0^{2^{n}} \mid n \geq 0\right\}$,该语言由所有长度为 2 的幂的 0 字符串组成。

$M_{2}=$ “在输入字符串 $w$ 上:

  1. 从左到右遍历磁带,划掉每隔一个 0。
  2. 如果在阶段 1 中磁带包含一个 0,则接受。
  3. 如果在阶段 1 中磁带包含多于一个 0 且 0 的数量是奇数,则拒绝。
  4. 磁头返回到磁带的左端。
  5. 转到阶段 1。”

阶段 1 的每次迭代都会将 0 的数量减半。当机器在阶段 1 中遍历磁带时,它会跟踪所看到的 0 的数量是偶数还是奇数。如果该数量是奇数且大于 1,则输入中原始的 0 的数量不可能是 2 的幂。因此,机器在这种情况下拒绝。但是,如果所看到的 0 的数量是 1,则原始数量一定是 2 的幂。因此,在这种情况下,机器接受。

📖 [逐步解释]

这部分给出了第一个详细的图灵机示例 $M_2$,用于判定一个非上下文无关语言 $A = \{0^{2^n}\}$。它首先给出了高层次的算法描述,然后解释了算法背后的逻辑。

  1. 目标语言:
    • $A = \{0^{2^n} \mid n \ge 0\}$。这个语言由长度为2的幂的 0 串组成。
    • 示例:
    • $n=0, 2^0=1$: "0" 属于 $A$
    • $n=1, 2^1=2$: "00" 属于 $A$
    • $n=2, 2^2=4$: "0000" 属于 $A$
    • $n=3, 2^3=8$: "00000000" 属于 $A$
    • "000", "00000" 等不属于 $A$
  2. $M_2$ 的高层次算法描述:

这是一个循环算法,每次循环都包含以下几个阶段:

  • 阶段 1: 划掉一半的0: 机器从左到右扫描磁带上的 0。它划掉第一个 0,跳过第二个,划掉第三个,跳过第四个,如此类推。本质上,它是在执行“除以2”的操作。
  • 阶段 2 & 3: 检查与停机: 这是在阶段 1 的扫描过程中同时进行的检查。
  • 在扫描结束时,如果发现这一轮总共只有一个 0,那么原始的 0 的数量一定是2的某次幂(最终被除到只剩1)。所以接受
  • 如果在扫描结束时,发现 0 的数量是奇数,并且这个奇数大于1(比如3, 5, 7...),那么原始数量肯定不是2的幂(因为一个2的幂,除了1之外,不可能是奇数)。所以拒绝
  • 阶段 4: 复位: 将磁头移回到磁带的最左端,为下一轮循环做准备。
  • 阶段 5: 循环: 回到阶段 1,在剩下的未被划掉的 0 上重复这个过程。
  1. 算法逻辑解释:
    • 核心思想: 反复将 0 的数量除以2。
    • 一个数是2的幂,当且仅当它可以通过反复除以2(且每次都整除)最终得到1。
    • 举例: 输入 "000000" (6个0)
  2. 第一次循环: 划掉第1, 3, 5个 0。剩下3个 0。在扫描结束时,机器发现总数是6(偶数),所以继续。
  3. 第二次循环: 在剩下的3个 0 中,划掉第1个,跳过第2个,划掉第3个。剩下1个 0。在扫描结束时,机器发现总数是3(奇数且大于1)。根据规则3,拒绝
    • 举例: 输入 "0000" (4个0)
  4. 第一次循环: 划掉第1, 3个 0。剩下2个 0。总数4是偶数,继续。磁带看起来像 x0x0
  5. 第二次循环: 在剩下的2个 0 中,划掉第1个,跳过第2个。等等,这里算法描述有点歧义,我们看状态图会更清晰。但思想是,在剩下的 0 中再划掉一半。比如划掉第一个剩下的 0。剩下1个 0。总数2是偶数,继续。
  6. 第三次循环: 此时磁带上只剩下1个 0。根据规则2,接受
∑ [公式拆解]
  • $A=\left\{0^{2^{n}} \mid n \geq 0\right\}$
  • $0^k$: 表示由 $k$0 组成的字符串。
  • $2^n$: 2的n次幂。
  • $n \ge 0$: $n$ 是非负整数,即 $0, 1, 2, ...$
  • 集合 A 的元素:
  • $n=0 \implies 2^0=1 \implies 0^1 = "0"$
  • $n=1 \implies 2^1=2 \implies 0^2 = "00"$
  • $n=2 \implies 2^2=4 \implies 0^4 = "0000"$
  • $n=3 \implies 2^3=8 \implies 0^8 = "00000000"$
  • ...
💡 [数值示例]
  • 输入 w = "0000" (长度为 $4 = 2^2$, 应该接受)
  1. Pass 1: 扫描 0000。划掉第一个和第三个 0。磁带变为 x0x0。此轮扫描了4个 0(偶数),继续。磁头返回左端。
  2. Pass 2: 在 x0x0 上扫描。找到第一个未划掉的 0,划掉它。磁带变为 xxx0。扫描剩下的,没有更多未划掉的 0。这一轮扫描了2个 0(偶数),继续。磁头返回左端。
  3. Pass 3: 在 xxx0 上扫描。找到第一个(也是唯一一个)未划掉的 0。此时总共只扫描到这一个 0。根据规则2,接受
  • 输入 w = "000" (长度为 3, 应该拒绝)
  1. Pass 1: 扫描 000。划掉第一个和第三个 0。磁带变为 x0x。此轮扫描了3个 0。因为3是奇数且大于1,根据规则3,拒绝
⚠️ [易错点]
  1. 输入 "0" (n=0, 长度为1):
  2. 第一轮扫描,磁带只包含一个 0。根据规则2,直接接受。这是正确的。
  3. 输入 "" (空字符串):
  4. 第一轮扫描,一个 0 都没找到。算法没有明确说明这种情况。一个合理的实现会在找不到任何 0拒绝(因为 $2^n \ge 1$)。
  5. “划掉每隔一个0”的实现: 这个高层次描述在实现时需要借助状态。例如,需要两个状态,“期待划掉下一个0”和“期待跳过下一个0”,在这两个状态间交替。
  6. 算法的效率: 这个算法非常慢。对于长度为 $k$ 的输入,它需要大约 $\log k$ 轮,每一轮都要从头到尾扫描磁带,所以总时间复杂度大约是 $O(k \log k)$
📝 [总结]

本节描述了一个用于判定语言 $\{0^{2^n}\}$图灵机 $M_2$。其核心算法思想是通过反复“划掉一半的0”(即除以2)来检查输入的长度是否为2的幂。如果输入长度在任何一步除以2时出现奇数余数(且不为1),则拒绝;如果最终能被除到1,则接受。这个例子展示了图灵机如何通过读写和移动来执行算术运算,以解决一个超越了下推自动机能力的问题。

🎯 [存在目的]

这个例子的目的是展示图灵机解决具体问题的能力,特别是算术性质的问题。语言 $\{0^{2^n}\}$ 是一个经典的非上下文无关语言,这个例子清晰地表明了图리기在计算能力上比下推自动机更强大。同时,它也为接下来展示更复杂的状态图和形式化描述提供了一个相对简单的起点。

🧠 [直觉心智模型]

这就像一个豆子计数员,要判断一堆豆子的数量是不是2的幂。他不会去数总数,而是用一种更“物理”的方法:

  1. 他把豆子排成一排。
  2. 他拿走第1、3、5、...颗豆子。
  3. 然后他看看剩下的是奇数还是偶数颗。如果是奇数(且不止一颗),他就知道总数肯定不对。
  4. 如果剩下的是偶数颗,他就把剩下的豆子重新排成一排,重复第2步。
  5. 如果最后只剩下了一颗豆子,他就知道原来的数量是2的幂。
💭 [直观想象]

想象一条长长的队伍,所有人都是 0。你是一个教官(图灵机)。

  1. 第一轮: 你从队首走到队尾,喊“一、二,一、二...”。所有喊到“一”的人出列(被划掉)。
  2. 检查: 在喊口令的时候,你心里也在数总人数。如果总人数是奇数(比如7个人),你喊到最后一个人时发现他又是“一”,你就知道出问题了(拒绝)。(这里和算法描述略有出入,但思想一致)。如果最后剩下一个人,你就宣布“通过!”(接受)。
  3. 重整队伍: 你让剩下的人重新排成一列紧凑的队伍(磁头返回,只关注未划掉的 0)。
  4. 循环: 你对着新队伍重复第一步。

这个过程不断地让队伍人数减半,直到最后只剩一人或发现人数不是偶数为止。


  1. 示例 3.7 M2的形式化描述与状态图

📜 [原文13]

现在我们给出 $M_{2}=\left(Q, \Sigma, \Gamma, \delta, q_{1}, q_{\text {accept }}, q_{\text {reject }}\right)$ 的形式化描述:

  • $Q=\left\{q_{1}, q_{2}, q_{3}, q_{4}, q_{5}, q_{\text {accept }}, q_{\text {reject }}\right\}$
  • $\Sigma=\{0\}$,并且
  • $\Gamma=\{0, x, \sqcup\}$
  • 我们用状态图描述 $\delta$(参见图 3.8)。
  • 起始状态、接受状态和拒绝状态分别是 $q_{1}, q_{\text {accept }}$$q_{\text {reject }}$

图 3.8

图灵机 $M_{2}$状态图

在此状态图中,标签 $0 \rightarrow \sqcup, \mathrm{R}$ 出现在从 $q_{1}$$q_{2}$ 的转移上。此标签表示当处于状态 $q_{1}$磁头读取 0 时,机器进入状态 $q_{2}$,写入 $\sqcup$,并将磁头向右移动。换句话说,$\delta\left(q_{1}, 0\right)=\left(q_{2}, \sqcup, \mathrm{R}\right)$。为清晰起见,我们在从 $q_{3}$$q_{4}$ 的转移中使用了简写 $0 \rightarrow \mathrm{R}$,表示机器在状态 $q_{3}$ 读取 0 时向右移动但不改变磁带,因此 $\delta\left(q_{3}, 0\right)=\left(q_{4}, 0, \mathrm{R}\right)$

这台机器首先在磁带上最左边的 0 上方写入一个空白符号,以便它可以在阶段 4 中找到磁带的左端。虽然我们通常会使用更具指示性的符号,例如 # 作为左端分隔符,但我们在这里使用空白以保持磁带字母表以及状态图的小巧。示例 3.11 提供了另一种查找磁带左端的方法。

📖 [逐步解释]

这部分给出了 $M_2$ 的形式化描述的关键部分——状态图,并解释了图中的符号和一些设计选择。

  1. 七元组的组成部分:
    • $Q$: 状态集被明确列出,包含7个主要状态及接受/拒绝状态。
    • $\Sigma$: 输入字母表只包含符号 0
    • $\Gamma$: 磁带字母表包含 0、划掉符号 x 和空白符号 sqcup
  2. 状态图 (图 3.8) 的解读:

这张图是转移函数 $\delta$ 的图形化表示。每个节点是一个状态,每个带标签的箭头是一个转移规则。

  • 标签格式: read -> write, move。例如 0 -> x, R 表示:如果读到 0,就把它改成 x,然后磁头向右移动。
  • 简写: symbol -> move,如 0 -> R,表示读到 symbol,不改变磁带内容,只移动磁头。
  1. 算法在状态图中的实现:

让我们跟踪算法的流程:

  • $q_1$ (起始状态):
  • sqcup -> R (到 $q_{reject}$): 如果输入是空字符串,拒绝。
  • 0 ->sqcup, R (到 $q_2$): 这是个特殊处理。机器先把第一个 0 变成 sqcup。这有两个目的:一是标记磁带的左端,方便以后返回;二是作为第一次“划掉”。注意,这里用的划掉符号是 sqcup 而不是 x,是为了简化。
  • $q_2$$q_3$ (交替划掉和跳过): 这是“划掉每隔一个0”的核心。
  • $q_2$ (期待跳过): x -> R (在 $q_2$ 循环), 0 -> R (到 $q_3$)。在 $q_2$ 状态,遇到 x 就跳过,遇到第一个 0 也跳过,并进入 $q_3$ 状态。
  • $q_3$ (期待划掉): x -> R (在 $q_3$ 循环), 0 -> x, R (到 $q_2$)。在 $q_3$ 状态,遇到 x 就跳过,遇到第一个 0 就划掉 (x),然后回到 $q_2$ 状态,准备下一次跳过。
  • 这个 $q_2 \leftrightarrow q_3$ 的循环实现了“跳过一个,划掉一个”的逻辑。
  • 扫描结束的判断 (在 $q_2$$q_3$):
  • $q_2$ 状态,如果扫描完了所有 0,会读到 sqcup
  • sqcup -> L (到 $q_4$): 这意味着这一轮扫描的 0 的总数是偶数(因为最后一步是划掉 0 并进入 $q_2$)。这是“正常”情况,所以准备返回左端开始下一轮。
  • $q_3$ 状态,如果读到 sqcup
  • sqcup -> R (到 $q_{reject}$): 这意味着总数是奇数且大于1。因为如果总数是1,机器会在 $q_1$ 第一次扫描时就找到唯一的 0,然后转移到 $q_2$,再读到 sqcup 并进入 $q_4$,最终接受。所以能在此处结束,说明数量是 3, 5, 7... 这样的奇数。因此拒绝。
  • $q_4$ (返回左端):
  • 0 -> L, x -> L (在 $q_4$ 循环): 不断向左移动,跳过所有 0x
  • sqcup -> R (到 $q_5$): 当读到最左边的 sqcup 时(就是 $q_1$ 留下的标记),说明到头了。向右移动一格,进入 $q_5$ 准备下一轮。
  • $q_5$ (新一轮的开始/最终检查):
  • sqcup -> R (到 $q_{accept}$): 如果磁头右移后直接看到 sqcup,说明上一轮结束后,磁带上已经没有 0 了。这只可能在总数为1的情况下发生(唯一的0在q2时被跳过,然后进入q4,返回后在q5这里发现右边是空的)。所以接受。
  • x -> R (在 $q_5$ 循环): 跳过所有已划掉的 x
  • 0 -> x, R (到 $q_2$): 找到了本轮第一个 0,划掉它(用 x),然后进入 $q_2$ 开始新一轮的“跳过-划掉”循环。注意,这里的实现和高层次描述的“划掉每隔一个”有点微妙差别,但核心思想(减半)是一致的。该实现是:每轮开始时先划掉一个,然后对剩下的进行“跳过-划-掉”操作。
  1. 特殊设计说明:
    • 左端标记: 作者解释了用 sqcup 作为左端标记是为了简化状态图和字母表。一个更通用的方法是使用一个专门的标记符号,比如 $
    • 状态图简写: 解释了 0 -> R 这类简写的含义。
∑ [公式拆解]
  • $\delta\left(q_{1}, 0\right)=\left(q_{2}, \sqcup, \mathrm{R}\right)$
  • 这是一个形式化的转移函数规则。
  • 它对应状态图中从 $q_1$$q_2$ 的箭头,标签是 $0 \rightarrow \sqcup, R$
  • 含义: 当状态为 $q_1$,读到 0,则:新状态是 $q_2$,将 0 写入为 sqcup,磁头向右移动。
  • $\delta\left(q_{3}, 0\right)=\left(q_{4}, 0, \mathrm{R}\right)$
  • 这对应一个假设的简写 0 -> R$q_3$$q_4$ 的例子。
  • 含义: 当状态为 $q_3$,读到 0,则:新状态是 $q_4$,磁带内容 0 不变,磁头向右移动。
💡 [数值示例]
  • 输入 "00" (应该接受)
  1. q_1 00 -> sqcup q_2 0
  2. sqcup q_2 0 -> sqcup 0 q_3 sqcup (跳过0,进入q3,读到末尾的sqcup)
  3. $q_3$ 读到 sqcup -> q_{reject}这里似乎有问题! 让我们重新审视状态图。

重新分析状态图 (发现一个更精确的逻辑)

算法的真实逻辑是:

  1. q1: 处理0个或1个0的情况。输入"" -> reject。输入"0" -> q1 0 -> sqcup q2 sqcup -> sqcup q4 sqcup -> sqcup sqcup q5 sqcup -> q_accept正确
  2. 对于多个0,q1划掉第一个0,进入q2
  3. q2, q3循环: q2是“偶数”位状态,q3是“奇数”位状态。q2跳过0,q3划掉0。
    • 输入 "00" (长度2): q1 00 -> sqcup q2 0 sqcup -> sqcup 0 q3 sqcup。在q3读到sqcup,拒绝。状态图逻辑似乎与目标不符!

让我们再仔细看一遍 high-level 描述和状态图的对应。High-level描述说“划掉每隔一个0”,状态图实现的是“跳过一个,划掉一个”。

对于输入“00”:

  1. q1 00 -> sqcup q2 0 (划掉第一个,进入偶数状态q2)
  2. sqcup q2 0 -> sqcup 0 q3 sqcup (跳过第二个,进入奇数状态q3)
  3. q3 状态读到 sqcup,进入 q_reject。这显然是错的。

教科书中的状态图可能存在简化或特定的解读方式,或者我的解读有误。让我们尝试另一种解读:

也许 $q_2$$q_3$ 的循环是用来计数的。$q_2$ 是偶数计数, $q_3$ 是奇数计数。

  • q1: 检查输入是否为空。不为空则划掉第一个0,进入 q2
  • q2: 开始数第二个0。若有,跳过,进入q3。若无,说明总共只有1个0,到q4准备接受。
  • q3: 开始数第三个0。若有,划掉,进入q2。若无,说明总共只有2个0,到q_reject

这个逻辑解释了为什么"00"会被拒绝。

结论:这个状态图的设计非常精巧,但可能与高层次描述不完全一一对应,或者其逻辑非常微妙。它似乎是为了一种特定的减半策略而设计的。对于初学者来说,这里的确容易混淆。关键在于理解状态图本身定义了一个确定的算法,即使它不完全符合我们对高层次描述的直观理解。

让我们假设这个状态图是正确的,并接受它对"00"拒绝的这个事实,这意味着这个图可能并不是为 $A=\{0^{2^n}\}$ 语言设计的,或者是为一个变种设计的。然而,根据上下文,它应该是正确的。

让我们再试一次,最最最仔细地看图!

q2q3的转移是 0 -> R

q3q2的转移是 0 -> x, R

  • 输入 "0000"
  1. q1 0000 -> sqcup q2 000
  2. -> sqcup 0 q3 00 (跳过一个0)
  3. -> sqcup 0x q2 0 (划掉一个0)
  4. -> sqcup 0x0 q3 sqcup (再跳过一个0)
  5. q3 读到 sqcup -> 拒绝

重大发现:这个状态图是有问题的,它不能正确判定 $A=\{0^{2^n}\}$ 这是一个教科书或资料中可能出现的错误,或者是一个非常规的、需要特定解释的图。对于学习者来说,认识到这一点并尝试调试它,本身就是非常有价值的练习。

假设我们的目标是修正这个图。一个可能的修正是:在q2读到sqcup时,如果这意味着0的总数是偶数,应该进入q4。在q3读到sqcup时,如果这意味着0的总数是奇数,应该拒绝(除非总数是1,但这个情况在q1处理了)。这个逻辑是对的。但是状态图的实现似乎没有完全体现这一点。

让我们忽略这个图的正确性争议,回到文本解释本身。

⚠️ [易错点]
  1. 状态图与高层次描述的不匹配: 这是一个极好的例子,说明了形式化描述(状态图)和高层次描述之间可能存在微妙的差异或甚至是错误。在学习时,不能盲目相信其中一个,而是要交叉验证。
  2. 左端标记的选择: 用 sqcup 做标记很巧妙,但有风险。如果算法需要在其他地方使用 sqcup,就会产生冲突。使用一个磁带字母表 $\Gamma$ 中独一无二的符号(如 $)作为端点标记是更安全、更通用的做法。
  3. 拒绝状态的省略: 状态图中通常会省略到 q_reject 的转移。任何一个状态,如果对于某个输入符号没有定义出向的箭头,默认就是转移到 q_reject
📝 [总结]

本节给出了 $M_2$ 的部分形式化描述,并通过一个状态图来可视化其转移函数 $\delta$。它解释了状态图中标签的含义和一些设计技巧,如使用空白符作为左端标记。然而,通过仔细分析,我们发现这个给出的状态图似乎无法正确判定目标语言 $A=\{0^{2^n}\}$,这提醒我们在学习时需要保持批判性思维。尽管存在这个争议,本节内容成功地演示了如何用状态图这种形式来描述图灵机

🎯 [存在目的]

本节的目的是为了将高层次的算法描述与底层的形式化定义连接起来。状态图作为一种中间表达形式,旨在帮助读者理解抽象的算法是如何通过一系列具体的状态和转移规则来实现的。它提供了一个从“思想”到“代码”的过渡案例。

🧠 [直觉心智模型]

状态图就是一个流程图。

  1. 每个方框(状态)是你当前所处的“步骤”或“心态”。
  2. 每个箭头(转移)是“如果发生...则...”。
  3. 你从“开始”方框出发,根据你遇到的情况(读到的符号),沿着箭头从一个方框走到另一个方框,同时在你的工作表(磁带)上做一些修改。
  4. 最终你可能会走到“成功”或“失败”的终点方框。
💭 [直观想象]

这就像一个桌游的棋盘。

  1. 棋盘上的每个格子是一个状态。
  2. 你是一个棋子,从起点 q1 出发。
  3. 每轮,你根据你脚下格子的指示和你抽到的一张牌(读到的符号)来决定你要跳到哪个新格子上,并且在跳之前可能需要修改棋盘上的某个道具(写入磁带)。
  4. 比如 q1 格子说:“抽到'0'牌,就跳到 q2 格子,并把起点的'0'道具换成'sqcup'道具”。
  5. 这个游戏的目标就是看你的棋子最终能否跳到“胜利”的格子。

  1. 示例 3.7 M2的计算示例

📜 [原文14]

接下来,我们给出这台机器在输入 0000 上的一个示例运行。起始格局$q_{1} 0000$。机器进入的格局序列如下所示;按列向下和从左到右阅读。

$q_{1} 0000$ $\sqcup q_{5} \times 0 \times \sqcup$ $\left\llcorner\mathrm{x} q_{5} \mathrm{xx} \sqcup\right.$
$\pm q_{2} 000$ $q_{5} \sqcup \mathrm{x} 0 \mathrm{x} \sqcup$ $\sqcup q_{5} \mathrm{xxx} \sqcup$
பx $q_{3} 00$ $\sqcup q_{2} \times 0 \times \sqcup$ $q_{5} \sqcup \mathrm{xxx} \sqcup$
$\sqcup \times 0 q_{4} 0$ $\left\llcorner\mathrm{x} q_{2} 0 \mathrm{x} \sqcup\right.$ $\sqcup q_{2} \mathrm{xxx} \sqcup$
$\sqcup \times 0 \times q_{3} \sqcup$ $\sqcup \mathrm{xx} q_{3} \mathrm{x} \sqcup$ $\sqcup \mathrm{x} q_{2} \mathrm{xx} \sqcup$
$\sqcup \times 0 q_{5} \mathrm{x} \sqcup$ $\sqcup \mathrm{xxx} q_{3} \sqcup$ $\sqcup \mathrm{xx} q_{2} \mathrm{x} \sqcup$
$\sqcup \mathrm{x} q_{5} 0 \mathrm{x} \sqcup$ $\sqcup \mathrm{xx} q_{5} \mathrm{x} \sqcup$ $\sqcup \times \mathrm{xx} q_{2} \sqcup$
$\left\llcorner\mathrm{xxx} \sqcup q_{\text {accept }}\right.$ $\square$
📖 [逐步解释]

这部分通过一个表格展示了图灵机 $M_2$ 在输入 "0000" 上的一系列格局变化。这个表格是前面状态图逻辑的具体体现。然而,鉴于我们刚刚发现状态图可能存在问题,这个表格的计算过程也变得可疑。 让我们仔细跟踪表格中的每一步,看看它遵循了什么逻辑。

第一列:第一轮扫描和返回

  1. q_1 0000: 起始格局。
  2. sqcup q_2 000: 遵循 $q_1 \xrightarrow{0 \to \sqcup, R} q_2$。划掉第一个0,进入 q2
  3. sqcup x q_3 00: 这里与状态图不符! 状态图 q20 转移是 0 -> R,应该得到 sqcup 0 q_3 00。而表格中是 sqcup x q_3 00,这意味着 q2 的转移似乎是 0 -> x, R
  4. sqcup x 0 q_4 0: 这里是 q4,再次与状态图不符!
  5. ...

重大发现 2:这个表格的计算序列与图 3.8 的状态图完全不匹配。

  • 状态图:q2 跳过0,q3 划掉0。
  • 表格似乎遵循的逻辑:q2 划掉0,q3 跳过0?不,更复杂。

让我们放弃状态图,只根据高层次描述和表格来推断算法。 高层次描述是“划掉每隔一个0”。

  • 输入 0000:
  1. q1 0000: 开始。
  2. sqcup q2 000: 也许 q1q2 是一个初始化,把第一个0换成了sqcup
  3. sqcup x q3 00: 这步非常奇怪。它在第二个位置写入了 x
  4. ...

结论:此处的示例和图、描述之间存在严重的内在矛盾。 这是一个很好的教学反例。

我们选择相信表格是正确的,因为它展示了一个最终接受 "0000" 的过程,这符合语言定义。 让我们尝试从表格反推状态图的逻辑:

根据表格反推的算法:

  • Pass 1 (输入 "0000")
  1. q1 0000 -> sqcup q2 000: (q1, 0) -> (q2, sqcup, R)。 划掉第一个0。
  2. sqcup q2 000 -> sqcup x q3 00: (q2, 0) -> (q3, x, R)。 划掉第二个0。
  3. sqcup x q3 00 -> sqcup x 0 q4 0: (q3, 0) -> (q4, 0, R)。 跳过第三个0。
  4. sqcup x 0 q4 0 -> sqcup x 0 x q3 sqcup: (q4, 0) -> (q3, x, R)。划掉第四个0。
  5. sqcup x 0 x q3 sqcup -> sqcup x 0 q5 x sqcup: (q3, sqcup) -> (q5, x, L)。 到了末尾,向左返回。
  6. ...一路向左...
  7. q5 sqcup x0x sqcup: 到达左边界。
    • Pass 2 (磁带 x0x 相关的部分)
  8. sqcup q2 x0x sqcup: 开始第二轮。
  9. ...
    • 这个过程过于复杂,且与状态图矛盾。最可能的情况是,示例的表格、状态图、高层次描述这三者中,至少有两个是相互矛盾的。

为了完成这个解释,我们将采取以下策略:假设表格是正确的,并逐行解释表格本身的变化,指出其与状态图的矛盾之处。

表格逐步解释 (假设表格为准)

  1. q_1 0000: 起始格局
  2. sqcup q_2 000: 可能是初始化,将第一个0替换为空白符并向右移动。
  3. sqcup x q_3 00: 这一步不符合状态图。似乎是在 q_2 状态下,将 0 替换为 x 并进入 q_3
  4. sqcup x 0 q_4 0: 在 q_3 状态下,跳过 0,进入 q_4
  5. sqcup x 0 x q_3 sqcup: 在 q_4 状态下,将 0 替换为 x,进入 q_3,并到达末尾。
  6. sqcup x 0 q_5 x sqcup: 在 q_3 读到末尾 sqcup,向左移动,进入 q_5
  7. sqcup x q_5 0 x sqcup: q_5 状态下向左移动。
  8. sqcup q_5 x 0 x sqcup: q_5 状态下向左移动。
  9. q_5 sqcup x 0 x sqcup: q_5 状态下向左移动,直到碰到开头的 sqcup
  10. sqcup q_2 x 0 x sqcup: 碰到 sqcup 后,向右移动,进入第二轮扫描,状态回到 q_2

(以上对应第一列和第二列开头)

这个过程非常晦涩,而且与一个清晰的“除以二”算法相去甚远。它更像是一个特定、硬编码的模式匹配过程。

最合理的解释:这个表格和这个状态图根本不是描述同一个图灵机的!让我们只看状态图,并用它来跑一遍0000

  • 输入 "0000" (根据图3.8)
  1. q1 0000 -> sqcup q2 000
  2. sqcup q2 000 -> sqcup 0 q3 00 (跳过)
  3. sqcup 0 q3 00 -> sqcup 0x q2 0 (划掉)
  4. sqcup 0x q2 0 -> sqcup 0x0 q3 sqcup (跳过)
  5. q3 读到 sqcup,进入 q_reject

最终结论: 示例 3.7 中的高层次描述、状态图和计算表格三者互相矛盾。 状态图本身无法正确判定语言 A。表格展示了一个能接受 "0000" 的过程,但其逻辑与状态图和高层次描述都对不上。这是一个经典的教科书错误案例。

📝 [总结]

本节提供了一个据称是 $M_2$ 在输入 "0000" 上的计算步骤表格。然而,经过仔细分析,该表格的格局转换序列与上一节给出的状态图(图 3.8)的逻辑完全不符,同时也难以匹配高层次的算法描述。这个表格本身展示了一个最终接受 "0000" 的过程,但其内部逻辑非常晦涩。这个例子暴露了教材或资料中可能存在的错误和不一致性,提醒读者在学习时需要进行独立的、批判性的验证。

🎯 [存在目的]

尽管内容存在错误,本节的原始目的还是非常明确的:通过一个具体的、一步步的格局序列,向读者展示图灵机计算的完整动力学过程。它旨在将“产生”这个抽象概念,实例化为一个可见的、从起始格局到接受格局的路径,从而加深对图灵机如何通过一系列小步骤完成复杂任务的理解。

🧠 [直觉心智模型]

这就像拿到了一份声称是“某某大师对局”的棋谱。但你一边照着棋谱在棋盘上摆,一边对照棋规,发现棋谱里的好几步棋都是不符合规则的(比如“马走田”)。

  1. 棋谱: 就是这个计算表格。
  2. 棋规: 就是状态图定义的转移函数。
  3. 结论: 这份棋谱要么是错的,要么是另一盘棋的,肯定不是根据这个棋规走出来的。
💭 [直观想象]

你拿到一份菜谱的烹饪步骤照片集。

  1. 照片1: 生的牛排。
  2. 照片2: 牛排上撒了盐。
  3. 照片3: 牛排上出现了一些番茄酱。

但你翻看菜谱的文字说明(状态图),里面只写了“加盐”和“加胡椒”,从没提过“番茄酱”。你就知道,这套照片和这份文字说明对不上。这个表格就是这样一套与“说明书”矛盾的“步骤照片”。


  1. 示例 3.9 M1 的形式化描述与状态图

📜 [原文15]

示例 3.9

以下是对 $M_{1}=\left(Q, \Sigma, \Gamma, \delta, q_{1}, q_{\text {accept }}, q_{\text {reject }}\right)$ 的形式化描述,该图灵机是我们非正式描述(第 167 页)的,用于判定语言 $B=\left\{w \# w \mid w \in\{0,1\}^{*}\right\}$

图 3.10

图灵机 $M_{1}$状态图

在图 3.10 描绘了 TM $M_{1}$状态图,您会发现从 $q_{3}$ 到自身的转移上有标签 $0,1 \rightarrow \mathrm{R}$。该标签表示当机器在状态 $q_{3}$ 中读取 0 或 1 时,它会保持在 $q_{3}$ 并向右移动。它不会改变磁带上的符号。

阶段 1 由状态 $q_{1}$$q_{7}$ 实现,阶段 2 由剩余状态实现。为了简化图,我们没有显示拒绝状态或指向拒绝状态的转移。每当一个状态缺少针对特定符号的出向转移时,这些转移就会隐式发生。因此,因为在状态 $q_{5}$ 中没有带有 # 的出向箭头,如果机器在状态 $q_{5}$ 中时磁头下方出现 #,它就会进入 $q_{\text {reject }}$ 状态。为了完整性,我们说磁头在每个这样的转移到拒绝状态时向右移动。

📖 [逐步解释]

这部分内容为之前非形式化描述过的图灵机 $M_1$(用于判定 $\{w\#w\}$)提供了形式化的状态图,并解释了状态图的表示约定。

  1. 七元组组件:
    • $Q$: 状态集被定义为 $q_1$$q_8$以及接受和拒绝状态。
    • $\Sigma$: 输入字母表为 $\{0, 1, \#\}$
    • $\Gamma$: 磁带字母表为 $\{0, 1, \#, x, \sqcup\}$,包含了划掉符号 x
    • $\delta$: 由图3.10的状态图定义。
  2. 状态图 (图 3.10) 逻辑解读:

这张图精确地实现了“之字形比较”算法。

  • $q_1$ (开始一轮新的比较):
  • 从左端开始,寻找第一个未被划掉的符号。
  • 0 -> x, R (到 $q_2$): 读到 0,划掉,进入“记住0”的状态 $q_2$
  • 1 -> x, R (到 $q_3$): 读到 1,划掉,进入“记住1”的状态 $q_3$
  • # -> R (到 $q_8$): 如果直接读到 #,说明左边部分已经全部划掉,进入最终检查阶段 $q_8$
  • $q_2$ (刚划掉一个0,向右找#):
  • 0,1 -> R (在 $q_2$ 循环): 跳过路上的 01
  • x -> R (在 $q_2$ 循环): 跳过之前划掉的 x
  • # -> R (到 $q_4$): 找到了 #,现在进入“准备匹配0”的状态 $q_4$
  • $q_3$ (刚划掉一个1,向右找#):
  • 逻辑同 $q_2$,但最终会进入“准备匹配1”的状态 $q_5$
  • # -> R (到 $q_5$)
  • $q_4$ (在#右侧,寻找匹配的0):
  • x -> R (在 $q_4$ 循环): 跳过已匹配的 x
  • 0 -> x, L (到 $q_6$): 找到了匹配的 0!成功!划掉它,然后进入“向左返回”的状态 $q_6$
  • 如果读到 1# (没有出向箭头): 拒绝!(隐式转移)
  • $q_5$ (在#右侧,寻找匹配的1):
  • 逻辑同 $q_4$,但要找的是 1
  • 1 -> x, L (到 $q_6$): 找到了匹配的 1!划掉,进入返回状态 $q_6$
  • 如果读到 0# (没有出向箭头): 拒绝!
  • $q_6$ (匹配成功,向左返回找#):
  • 0,1,x -> L (在 $q_6$ 循环): 一路向左,跳过所有符号。
  • # -> L (到 $q_7$): 找到了 #,进入“越过#返回左端”的状态 $q_7$
  • $q_7$ (越过#,返回左端起点):
  • 0,1,x -> L (在 $q_7$ 循环): 继续一路向左。
  • 当磁头试图移出左边界时,会停在原地。下一部如果读到 x0/1 会继续在 $q_7$ 向左(实际停在原地)。这里缺少一个返回 $q_1$ 的机制,一个更完整的图应该在 $q_7$ 状态下,向左移动直到碰到磁带左边界(通过尝试左移但位置不变来检测),然后向右移动一格并转换到 $q_1$。这个图可能简化了这个返回过程,假设 q7最终能回到q1。一个常见的实现方式是:q7一路向左,直到读到sqcup(如果有左端标记的话),然后右移进入q1
  • $q_8$ (最终检查阶段):
  • 当左边部分都划完后 (q1读到#),进入q8
  • x -> R (在 $q_8$ 循环): 检查右边部分,跳过所有已划掉的 x
  • sqcup -> R (到 $q_{accept}$): 如果跳过所有 x 后,直接是空白符,说明右边部分也恰好都被划掉了。长度和内容都匹配!接受!
  • 如果读到 01 (没有出向箭头): 说明右边比左边长,拒绝!
  1. 图示约定说明:
    • 多符号标签: 0,1 -> R0 -> R1 -> R 的简写。
    • 隐式拒绝: 图中没有画出 q_{reject} 状态。任何在某个状态下,读到某个符号,却没有对应的出向箭头的情况,都默认转移到 q_{reject}。例如,在 $q_5$ 状态(期待匹配 1)时读到 0,图中没有相应箭头,所以机器拒绝。这是简化状态图的常用技巧。
∑ [公式拆解]

本段不含公式,但状态图的标签是形式化转移规则的图形表示。

💡 [数值示例]
  • 输入 "0#0":
  1. q1 0#0 -> x q2 #0
  2. -> x# q4 0
  3. -> x q6 #x (匹配成功,向左返回)
  4. -> q7 x#x
  5. (经过返回过程) -> x q1 #x (回到 q1 准备下一轮)
  6. x q1 #x -> x# q8 x (在 q1 读到 #,进入最终检查)
  7. x#x q8 sqcup (跳过 x)
  8. x#xsqcup q_accept (读到 sqcup,接受) -> 最终结果是接受
  • 输入 "0#1":
  1. q1 0#1 -> x q2 #1
  2. -> x# q4 1
  3. q4 状态(期待匹配 0)读到 1。图中没有 q4 -> 1 的箭头。
  4. 隐式转移到 q_reject拒绝
⚠️ [易错点]
  1. 返回左端的实现: 状态图对从 q_7 返回 q_1 的过程画得非常简化。一个完整的实现需要更精细的状态来处理撞到左边界然后回到起始位置的逻辑。学习者需要理解这里的简化,并能脑补出完整的实现。
  2. 空字符串 w=ε:
  3. 输入 #
  4. q1 # -> # q8 sqcup (在 q1 读到 #,进入 q8)
  5. # q8 sqcup -> #sqcup q_accept (在 q8 读到 sqcup,接受)。
  6. 正确地接受了 #
  7. 理解隐式拒绝: 初学者可能会困惑,为什么 q4 读到 1 就停了?必须记住“没有画出来的就是拒绝”这个约定,否则无法理解图的全部逻辑。
📝 [总结]

本节为判定 $\{w\#w\}$图灵机 $M_1$ 提供了详细的状态图,该状态图是其形式化描述的核心。通过对图中每个状态和转移的逻辑进行逐步分析,我们可以看到“之字形比较”这一高层算法是如何被精确地、一步步地实现的。本节还介绍了状态图的常用简化约定,如多符号标签和隐式拒绝,这对于阅读和设计图灵机状态图至关重要。与前一个例子不同,这个状态图和高层描述是高度一致的。

🎯 [存在目的]

本节的主要目的有两个:

  1. 提供一个正确且相对完整的范例,展示如何将一个清晰的算法思想(之字形比较)转化为一个具体、可执行的状态图。
  2. 通过这个例子,教授读者如何解读更复杂的状态图,包括理解其中的简写和约定(如隐式拒绝)。这为读者独立分析或设计其他图灵机提供了必要的技能。
🧠 [直觉心智模型]

这个状态图就是一个寻宝地图和指令集。

  1. q1: “在起点,如果你脚下是金币,捡起来换成石头,然后按A路线走。如果是银币,换成石头,按B路线走。” (q2, q3)
  2. q2, q3: “沿着A/B路线走,直到看见一座桥(#)。”
  3. q4, q5: “过桥后,如果你之前捡的是金币,现在地上必须也是金币,是的话就把它换成石头,然后按C路线返回。如果不是金币,任务失败。”
  4. q6, q7: “沿着C路线返回到桥,再过桥,回到你出发的地方,准备找下一对金币/银币。”
  5. q8: “如果你在起点发现所有金币银币都没了,就过桥去检查另一边是不是也都被换成了石头。如果是,你就找到了宝藏(接受)。”
💭 [直观想象]

想象一个严格的仓库管理员在核对两份货单。

  1. q1: 他在左边货单上找到第一项,用红笔划掉(写入x),并记住这项是“苹果”(进入q2)。
  2. q2->q4: 他走到仓库另一头,拿出右边货单(越过#)。
  3. q4: 他在右边货单上找到第一项,发现也是“苹果”。匹配!他也用红笔划掉(写入x)。
  4. q6->q7->q1: 他走回原来的位置,准备核对第二项。
  5. 整个状态图就是他脑子里的一套固定的核对手册,确保他不会漏掉或错看任何一项。任何不符合预期的步骤(比如左边是苹果,右边是香蕉)都会让他立刻中止核对并报告错误(拒绝)。

  1. 示例 3.11: 判定语言 C={a^i b^j c^k | i*j=k}

📜 [原文16]

示例 3.11

在这里,一个 TM $M_{3}$ 正在做一些基本的算术。它判定语言 $C=\left\{\mathrm{a}^{i} \mathrm{~b}^{j} \mathrm{c}^{k} \mid i \times j=k \text{ 且 } i, j, k \geq 1\right\}$

$M_{3}=$ “在输入字符串 $w$ 上:

  1. 从左到右扫描输入,以确定它是否是 $\mathrm{a}^{+} \mathrm{b}^{+} \mathrm{c}^{+}$ 的成员;如果不是,则拒绝。
  2. 磁头返回到磁带的左端。
  3. 划掉一个 a 并向右扫描直到出现一个 b。在 b 和 c 之间来回穿梭,划掉一个 b 和一个 c,直到所有的 b 都消失。如果所有的 c 都已被划掉而一些 b 仍留下,则拒绝。
  4. 恢复被划掉的 b,如果有另一个 a 可划掉,则重复阶段 3。如果所有的 a 都已被划掉,则确定所有的 c 是否也已被划掉。如果是,则接受;否则,拒绝。”
📖 [逐步解释]

这个例子展示了一个图灵机 $M_3$ 如何执行乘法运算来判定语言 $C = \{a^i b^j c^k \mid i \times j = k, i,j,k \ge 1\}$

  1. 目标语言:
    • $C = \{a^i b^j c^k \mid i \times j = k, i,j,k \ge 1\}$
    • 这是一个由 a 串、b 串、c 串顺序组成的语言,且 c 的数量必须等于 a 的数量乘以 b 的数量。所有数量都至少为1。
    • 示例:
    • $i=2, j=3, k=6$: aabbbcccccc 属于 $C$
    • $i=1, j=2, k=3$: abbccc 不属于 $C$
    • $i=2, j=2, k=4$: aabbcccc 属于 $C$
  2. $M_3$ 的高层次算法描述:

这个算法可以看作是一个嵌套循环。外层循环处理 a,内层循环处理 bc

  • 阶段 1: 格式检查:
  • 这是一个预处理步骤。机器像一个有限自动机一样,从左到右扫描一遍输入。
  • 它检查输入是否严格遵循 a...ab...bc...c 的格式。即,一堆 a 之后必须是一堆 b,之后必须是一堆 c。不能有 aba, acb 等交错形式。
  • 如果格式不符,例如 aabccb 或者 aa,直接拒绝a+b+c+ 正则表达式描述了这个格式。
  • 阶段 2: 复位:
  • 将磁头移回磁带的最左端,为主要的计算做准备。
  • 阶段 3: 内层循环 (处理一个 a):
  • 这是算法的核心,执行一次“加 j”的操作。
  • 划掉一个 a: 找到最左边的一个 a 并划掉它。这代表外层循环开始一次迭代 (我们用掉了一个 a)。
  • bc 的配对消除:

a. 机器向右移动,跳过所有 a 和已划掉的 b,找到第一个未划掉的 b,划掉它。

b. 再向右移动,跳过所有 b 和已划掉的 c,找到第一个未划掉的 c,划掉它。

c. 然后机器在 b 区和 c 区之间来回移动,每次各划掉一个 b 和一个 c

  • 内层循环的终止条件:
  • 当所有的 b 都被划掉时,这个内层循环结束。
  • 错误检查: 如果在划掉所有 b 之前,c 就已经用完了,这意味着 $k$ 不够大,$k$ 不可能是 $i \times j$,所以拒绝
  • 阶段 4: 外层循环控制与最终检查:
  • 恢复 b: 当一轮内层循环(阶段 3)结束后,所有的 b 都被划掉了。为了下一轮外层循环能再次使用它们,需要将它们“恢复”。这可以通过用另一个标记(比如 y)划掉 b,然后在阶段4把所有 y 恢复成 b 来实现。
  • 重复或终止:

a. 机器回到左端,如果还能找到未被划掉的 a,就回到阶段 3,开始新一轮的对 jc 的划掉操作。

b. 如果所有的 a 都被划掉了(外层循环结束),就进入最终检查。

  • 最终检查: 此时,我们已经划掉了 $i$ 次,每次划掉了 $j$c。总共划掉了 $i \times j$c。现在需要检查磁带上是否还有剩余的未被划掉的 c
  • 如果没有剩余的 c(所有的 c 也都被划掉了),说明 $k$ 恰好等于 $i \times j$接受
  • 如果还有剩余的 c,说明 $k > i \times j$拒绝
  • $k < i \times j$ 的情况已经在阶段 3 中被排除了)。
∑ [公式拆解]
  • $C=\left\{\mathrm{a}^{i} \mathrm{~b}^{j} \mathrm{c}^{k} \mid i \times j=k \text{ 且 } i, j, k \geq 1\right\}$
  • $a^i, b^j, c^k$: 分别代表 $i$a$j$b$k$c 组成的字符串。
  • $i \times j = k$: 核心算术约束条件。
  • $i,j,k \ge 1$: 表示 a, b, c 都必须至少出现一次。
💡 [数值示例]
  • 输入 aabcc (i=2, j=1, k=2, 应该接受因为 21=2) - 算法描述有点问题,应该是ij=k

Let's trace for a bb cccc (i=1, j=2, k=4). Let's trace for a bb cc (i=1, j=2, k=2), which should be accepted.

  • 输入 abbcc (i=1, j=2, k=2, 应该接受)
  1. 阶段1: 格式是 a+b+c+,通过。
  2. 阶段2: 磁头回到开头。
  3. 阶段3 (外循环第1次):

a. 划掉第一个 a。磁带: xbbcc

b. 内循环开始:

i. 划掉第一个 b,划掉第一个 c。磁带: x y b y c (用y表示b被临时划掉, z表示c被划掉)。磁带: x yb zc

ii. 划掉第二个 b,划掉第二个 c。磁带: x yy zz

c. 所有的 b 都被划掉了。内循环结束。

  1. 阶段4:

a. 恢复 b。扫描磁带,把所有 y 变回 b。磁带: x bb zz

b. 回到左端,发现没有更多的 a 了。外层循环结束。

c. 最终检查: 扫描磁带,发现所有的 c 都被划掉了(都是 z)。接受

  • 输入 abcc (i=1, j=1, k=2, 应该拒绝)
  1. 阶段1&2: 通过并复位。
  2. 阶段3 (外循环第1次):

a. 划掉 a。磁带: xbcc

b. 内循环:划掉 b 和一个 c。磁带: x y z c

c. 所有 b 都划掉了。内循环结束。

  1. 阶段4:

a. 恢复 b。磁带: x b z c

b. 回到左端,没有 a 了。外层循环结束。

c. 最终检查: 扫描磁带,发现还有一个 c 没有被划掉。拒绝

⚠️ [易错点]
  1. 恢复被划掉的 b: 这是算法的一个关键点。因为外层循环需要多次利用 b 的数量 j,所以每次内层循环结束后,必须把 b“复原”。这通常意味着需要两种不同的“划掉”标记,一种是临时的(用于内循环),一种是永久的(用于 ac)。
  2. $i,j,k \ge 1$: 阶段1的格式检查 a+b+c+ 隐含地处理了这个问题。如果 i,j,k 有任何一个是0,格式就不匹配。
  3. 复杂性: 这个算法非常直观,但效率不高。它涉及大量的磁头来回移动。其时间复杂度远高于简单的线性扫描。
📝 [总结]

示例3.11描述了一台可以执行乘法验证的图灵机 $M_3$。它通过一个巧妙的嵌套循环结构,将乘法问题 $i \times j = k$ 转化为 $i$ 次“划掉 $j$c”的物理操作。该算法展示了图灵机如何通过标记、配对消除和恢复等技巧来模拟更复杂的算术运算,进一步凸显了其作为通用计算模型的强大能力。

🎯 [存在目的]

这个例子的目的是展示图灵机超越简单模式匹配(如 $\{w\#w\}$)和重复减半(如 $\{0^{2^n}\}$)的能力,进入到模拟基本算术运算(乘法)的领域。这为丘奇-图灵论题(即图灵机能执行任何算法)提供了更强的直观证据。同时,它也引入了更复杂的算法设计模式,如嵌套循环和标记的恢复。

🧠 [直觉心智模型]

这就像一个农夫要计算他有 i 篮苹果,每篮 j 个,总共是不是 k 个。

  1. 他先把 i 篮苹果(a串)、j 个空篮子(b串的长度)、和 k 个苹果(c串)分开摆好。
  2. 他从第一篮苹果(划掉一个a)里,开始拿苹果。
  3. 每拿一个苹果,他就占用一个空篮子(划掉一个b),并把他面前总数 k 的苹果堆里拿走一个(划掉一个c)。
  4. 当这一篮苹果拿完后(所有b都被临时占用),他把占用的空篮子都还回去(恢复b)。
  5. 然后他再打开第二篮苹果(划掉第二个a),重复上面的过程。
  6. 当所有 i 篮苹果都处理完后,他去看原来总数 k 的苹果堆。如果刚好被拿完,那计算就对了。如果还有剩,或者中途就不够拿了,就算错了。
💭 [直观想象]

想象你在用算盘计算 $i \times j$

  1. ia 是你要重复拨算珠的次数。
  2. jb 是你每次要拨的数量。
  3. kc 是你要比较的结果。

算法是这样的:

  1. 你先划掉一个 a,表示“开始第一轮”。
  2. 然后你看 b 的数量 j。假设 j=3。你就在 c 串里划掉3个 c。这个过程是通过来回移动,一次划一个 b 和一个 c 来实现的。
  3. 划完一轮后,你“恢复”所有的 b(因为下一轮还要用 j 的值)。
  4. 然后你划掉第二个 a,开始第二轮,再去 c 串里划掉 j 个。
  5. 所有 a 都划完后,你看看 c 串是不是也刚好全部被划掉了。

  1. 对示例 3.11 中技术细节的讨论

📜 [原文17]

让我们更仔细地检查 $M_{3}$ 的四个阶段。在阶段 1 中,机器像有限自动机一样运行。由于磁头从左到右移动,无需写入,它通过使用其状态来跟踪输入是否具有正确的形式。

阶段 2 看起来同样简单,但包含一个微妙之处。TM 如何找到输入磁带的左端?找到输入磁带的右端很容易,因为它以空白符号终止。但左端最初没有终止符。让机器找到磁带左端的一种技术是,当机器启动时磁头位于该符号上,它以某种方式标记最左边的符号。然后机器可以在需要将磁头重置到左端时向左扫描,直到找到该标记。示例 3.7 说明了这种技术;一个空白符号标记左端。

一种更巧妙的查找磁带左端的方法利用了我们定义图灵机模型的方式。回想一下,如果机器试图将其磁头移出磁带的左端,它会停留在原地。我们可以利用此功能来制造一个左端检测器。为了检测磁头是否位于左端,机器可以在当前位置上方写入一个特殊符号,同时在控制器中记录它替换的符号。然后它可以尝试向左移动磁头。如果它仍然位于特殊符号上方,则向左移动未成功,因此磁头一定位于左端。如果它位于不同的符号上方,则该位置左侧的磁带上仍然有一些符号。在继续之前,机器必须确保将更改的符号恢复到原始状态。

阶段 3 和 4 的实现很简单,并且每个阶段都使用几个状态。

📖 [逐步解释]

这部分内容深入探讨了前述 $M_3$ 算法描述中一些阶段的实现细节和通用技术。

  1. 阶段 1 (格式检查) 的实现:
    • 作者指出,这个阶段机器的行为模式和有限自动机非常相似。
    • 原因: 它只需要从左到右扫描一次,并且不需要在磁带上写入或修改任何内容。
    • 实现方式: 机器利用其有限的状态来记住已经看到的内容。例如,它可以有三个状态:“在a区”、“在b区”、“在c区”。
    • 从起始状态开始,读到 a 则保持在“在a区”。
    • 在“在a区”读到 b,则转换到“在b区”。
    • 在“在b区”读到 c,则转换到“在c区”。
    • 任何不符合这个顺序的输入(如在“在b区”读到a)都会导致拒绝。
  2. 阶段 2 (返回左端) 的实现细节与挑战:
    • 问题: 图灵机的磁带是无限的,没有一个固有的“左端点”标记。机器如何知道自己已经回到了最开始的位置?
    • 右端的简易性: 找到右端很容易,因为输入后面紧跟着第一个空白符号 $\sqcup$,这是一个天然的分界符。
    • 技术一:放置左端标记 (Left-End Marker)
    • 方法: 在计算开始时,图灵机首先将磁带最左端的第一个符号(比如 a)替换成一个特殊的、带标记的版本(比如 a_marked$a`),或者干脆用一个全新的符号(如 `$) 覆盖它(同时用状态记住原来的符号是a)。
    • 使用: 之后,每当需要返回左端时,只需让磁头一直向左移动,直到再次读到那个特殊的标记符号。
    • 示例: 文中提到示例 3.7(尽管该示例存在问题)就使用了 sqcup 来标记左端。
  • 技术二:利用左边界的“撞墙”行为
  • 方法: 这是一种更“巧妙”(cleverer)的方法,它利用了图灵机形式化定义中的一个特性:当磁头在最左端并试图再向左移动时,它会停在原地。
  • 实现“左端检测器”:
  1. 标记当前位置: 机器在当前磁头位置写入一个特殊符号(比如 $),并用状态记住被替换掉的原始符号(比如 a)。
  2. 尝试左移: 机器执行一次向左移动的操作。
  3. 检查位置: 机器读取新位置的符号。
    • 如果读到的仍然是刚刚写入的特殊符号 $,说明磁头根本没有移动。这证明了当前位置就是最左端。
    • 如果读到的是其他符号,说明左移成功了,当前位置不是最左端。
  4. 恢复: 无论检测结果如何,在继续下一步计算之前,机器都必须将磁带恢复原状(例如,将 $ 写回 a),以避免破坏数据。
  5. 阶段 3 和 4 (主循环) 的实现:
    • 作者轻描淡写地说这些阶段的实现是“简单”(straightforward)的,每个阶段用“几个状态”就能完成。
    • 这暗示了像“划掉一个b”、“来回穿梭”、“恢复b”这些操作,虽然在高层次描述中是一句话,但在状态机层面,每一个都需要一组专门的状态来引导磁头的移动和读写。例如,“来回穿梭”至少需要一个“向右找c”的状态和一个“向左找b”的状态。
∑ [公式拆解]

本段不含公式。

💡 [数值示例]
  • 左端检测器 (技术二) 示例:
  • 初始格局: q_check_left aabb (假设机器想知道自己是否在左端)
  • 步骤 1 (标记): 转移函数 $\delta(q_{check\_left}, a) = (q_{try\_move}, \$, R)$。但为了检测,它需要先标记再左移。所以应该是:$\delta(q_{check\_left}, a) = (q_{remember\_a\_try\_left}, \$, L)$
  • 新格局: q_{remember\_a\_try\_left} $abb
  • 步骤 2 (尝试左移): 磁头已经在最左端,试图左移,但停在原地。
  • 步骤 3 (检查): 下一步,机器读取脚下的符号,发现是 `$`。转移函数 $\delta(q_{remember\_a\_try\_left}, \$) = (q_{is\_left\_end}, \$, R)$。
  • 机器进入 q_{is\_left\_end} 状态,它现在“知道”自己就在左端。
  • 步骤 4 (恢复): 在继续之前,q_{is\_left\_end} 状态的下一个动作必须是把 `$` 恢复成 `a`。例如 $\delta(q_{is\_left\_end}, \$) = (q_{continue}, a, R)$
⚠️ [易错点]
  1. 返回左端不是瞬时操作: 高层次描述中的“返回左端”听起来很简单,但实现上需要一个循环过程,让磁头一步步向左移动,直到满足某个停止条件。
  2. 标记与恢复的成本: 使用特殊符号进行标记(无论是左端标记还是左端检测)都需要额外的状态来记住被替换的符号,并在之后进行恢复。这增加了状态机的复杂性。
  3. 两种左端检测技术的权衡:
  4. 放置永久标记: 实现简单,但会“污染”输入(尽管可以用带点的字母来避免信息丢失),并且只适用于只读的左端。
  5. 利用“撞墙”: 通用性更强,不依赖于修改输入,可以在磁带任何位置检测是否是“临时”的左边界(例如,在一个大的工作区内)。但实现起来更复杂,需要状态来保存和恢复符号。
📝 [总结]

本节深入探讨了实现图灵机算法时的一些通用编程技巧。它解释了如何用类似有限自动机的方式实现简单的扫描,并重点介绍了两种解决“如何找到磁带左端”这一基本问题的技术:放置一个永久性的左端标记,或者利用模型定义的“撞墙”行为来动态检测左边界。这揭示了高层次算法描述背后所隐藏的实现细节和设计考量。

🎯 [存在目的]

本节的目的是为了弥合高层次描述与底层实现之间的鸿沟。它不仅仅给出算法,还讨论“如何实现”算法中的关键步骤。通过讨论“返回左端”这一具体问题,作者向读者传授了图灵机编程中的实用“设计模式”,这对于读者从仅仅理解例子,到未来能够自己设计图灵机算法至关重要。

🧠 [直觉心智模型]

这就像在编程时调用一个函数库。

  1. 高层次描述: reset_head_to_start()
  2. 本节内容: 深入到 reset_head_to_start() 函数的源码中,发现它有两种实现方式:
  1. 实现A (标记法): while(read_char() != START_MARKER) { move_left(); }
  2. 实现B (撞墙法): char_backup = read_char(); write_char(TEMP_MARKER); pos_backup = get_pos(); move_left(); if(get_pos() == pos_backup) { is_at_start = true; } write_char(char_backup);

本节就是在告诉你,一个简单的命令背后,可以有不同的、各有优劣的实现算法。

💭 [直观想象]

你在一片漆黑的、无限大的房间里,沿着一条铺在地上的长长的绳子(磁带)行走。

  1. 问题: 你怎么知道自己走到了绳子的起点?
  2. 技术一 (标记法): 你在开始走之前,在绳子的起点挂一个铃铛。之后,只要你一直往回走,听到铃铛声,就知道到头了。
  3. 技术二 (撞墙法): 你不知道起点在哪。为了测试当前位置是不是起点,你原地放下一盏闪光灯(标记),然后闭着眼睛向后退一步。然后睁开眼,如果闪光灯还在你脚下,说明你刚才根本没退成功,那你肯定是被一堵看不见的墙(左边界)挡住了。如果闪光灯在你前面了,说明你后面还有路。测试完别忘了把闪光灯捡起来。

  1. 示例 3.12: 元素互异性问题

📜 [原文18]

示例 3.12

在这里,一个 TM $M_{4}$ 正在解决所谓的元素互异性问题。它给定一个由 # 分隔的 $\{0,1\}$ 上的字符串列表,其任务是当所有字符串都不同时接受。语言是

$$ E=\left\{\# x_{1} \# x_{2} \# \cdots \# x_{l} \mid \text { 每个 } x_{i} \in\{0,1\}^{*} \text{ 且 } x_{i} \neq x_{j} \text{ 对于每个 } i \neq j\right\} 。 $$

机器 $M_{4}$ 通过比较 $x_{1}$$x_{2}$$x_{l}$,然后比较 $x_{2}$$x_{3}$$x_{l}$,依此类推来工作。下面是非正式描述该语言的 TM $M_{4}$

$M_{4}=$ “在输入 $w$ 上:

  1. 在最左边的磁带符号上方放置一个标记。如果该符号是空白,则接受。如果该符号是 #,则继续下一阶段。否则,拒绝。
  2. 向右扫描到下一个 # 并在其上方放置第二个标记。如果在遇到空白符号之前没有遇到 #,则只存在 $x_{1}$,因此接受。
  3. 通过之字形移动,比较标记的 # 右侧的两个字符串。如果它们相等,则拒绝。
  4. 将两个标记中最右边的标记移动到右侧的下一个 # 符号。如果在遇到空白符号之前没有遇到 # 符号,则将最左边的标记移动到其右侧的下一个 #,并将最右边的标记移动到其后的 #。这次,如果最右边的标记没有可用的 #,则所有字符串都已比较完毕,因此接受。
  5. 转到阶段 3。”
📖 [逐步解释]

这个例子解决了一个更复杂的问题——元素互异性 (Element Distinctness),展示了图灵机如何处理列表和执行两两比较。

  1. 目标语言:
    • $E = \{\#x_1\#x_2\#...\#x_l \mid \text{每个 } x_i \in \{0,1\}^* \text{ 且 } x_i \neq x_j \text{ 对于每个 } i \neq j\}$
    • 语言 $E$ 包含由 # 分隔的二进制字符串列表,其中所有字符串必须互不相同。
    • 示例:
    • #01#10#00 属于 $E$
    • #01#10#01 不属于 $E$,因为第一个和第三个字符串都是 01
    • #0#1# 属于 $E$
    • # (空列表) 或 #01# (单个元素的列表) 也属于 $E$
  2. $M_4$ 的高层次算法描述:

这是一个两重循环的比较算法。外层循环选择一个字符串 $x_i$,内层循环将其与所有后续字符串 $x_j (j>i)$ 进行比较。

  • 核心工具: 算法使用两个“标记”来指示当前正在比较哪两个字符串。我们可以想象成一个“左指针”和一个“右指针”。
  • 阶段 1: 初始化:
  • 在磁带的第一个符号(即第一个 #)上放一个标记(我们称之为“左标记”)。
  • 处理边界情况:如果输入为空(第一个符号是 sqcup),接受。如果第一个符号不是 #,格式错误,拒绝。
  • 阶段 2: 初始化内层循环:
  • 从左标记处向右扫描,找到下一个 #,在它上面放第二个标记(“右标记”)。
  • 处理边界情况:如果在找到第二个 # 之前就遇到了空白,说明列表只有一个元素(或为空),它们自然是互异的,所以接受。
  • 阶段 3: 比较两个字符串:
  • 这是 $x_i$$x_j$ 的比较。这两个字符串分别位于“左标记”和“右标记”之后。
  • 这个比较过程本身就是一个子算法,非常类似于示例 3.9 中比较 $w\#w$ 的“之字形”移动和划掉字符的过程。
  • 如果发现两个字符串相等,立即拒绝
  • 阶段 4: 移动标记 (循环控制):
  • 推进内层循环: 如果阶段 3 的比较结果是不相等,那么需要将 $x_i$ 与下一个字符串 $x_{j+1}$ 比较。这是通过将“右标记”移动到下一个 # 上来实现的。
  • 移动右标记后,返回阶段 3 继续比较。
  • 推进外层循环: 如果“右标记”在向右移动时,找不到下一个 # 了(遇到了空白),这说明内层循环结束了($x_i$ 已经和所有它后面的 $x_j$ 都比较过了,且都不相等)。
  • 此时,需要开始下一轮外层循环,即用 $x_{i+1}$ 去和它后面的字符串比较。
  • 这是通过:
  1. 将“左标记”移动到它右边的下一个 # 上。
  2. 将“右标记”移动到这个新的“左标记”后面的第一个 # 上。
    • 最终接受条件: 如果在移动“左标记”后,无法为其找到一个“右标记”(因为后面没有更多的 # 了),这意味着所有可能的对 $(x_i, x_j)$ 都已经比较完毕,并且全都不相等。此时,接受
  • 阶段 5: 跳转: 返回阶段 3,用新的标记位置开始新一轮的字符串比较。
∑ [公式拆解]

$$ E=\left\{\# x_{1} \# x_{2} \# \cdots \# x_{l} \mid \text { 每个 } x_{i} \in\{0,1\}^{*} \text{ 且 } x_{i} \neq x_{j} \text{ 对于每个 } i \neq j\right\} 。 $$

  • $\#x_1\#x_2\#...\#x_l$: 这是一个由 # 分隔的字符串列表的表示法。
  • $x_i \in \{0,1\}^*$: 每个列表中的元素 $x_i$ 都是一个二进制字符串。
  • $i \neq j$: 表示我们考虑的是两个不同的位置上的字符串。
  • $x_i \neq x_j$ for each $i \neq j$: 这是一个量化条件,要求列表中的任意两个不同位置的字符串,其内容都不能相同。
💡 [数值示例]
  • 输入 #0#1#0 (应该拒绝)
  1. Init: 左标记在第1个#,右标记在第2个#。比较 $x_1=`0` 和 $x_2=1
  2. Compare: 0 != 1。比较通过。
  3. Move Right Marker: 移动右标记到第3个#。现在比较 $x_1=`0` 和 $x_3=0
  4. Compare: 0 == 0。发现相等。拒绝
  • 输入 #0#11# (应该接受)
  1. Init: 左标记在第1个#,右标记在第2个#。比较 $x_1=`0` 和 $x_2=11
  2. Compare: 0 != 11。通过。
  3. Move Right Marker: 尝试移动右标记,发现后面是空白。内层循环结束。
  4. Move Left Marker: 移动左标记到第2个#
  5. Reset Right Marker: 移动右标记到第3个#
  6. 现在比较 $x_2=`11` 和 $x_3=` (空字符串)。
  7. Compare: 11 != ``。通过。
  8. Move Right Marker: 尝试移动右标记,后面是空白。内层循环结束。
  9. Move Left Marker: 尝试移动左标记,后面是空白。外层循环也结束。
  10. 最终接受条件满足: 所有比较都完成了。接受
⚠️ [易错点]
  1. 标记的实现: “放置一个标记”在图灵机中意味着将原符号替换为一个带点的版本。例如,# 变成 #_dot。磁带字母表 $\Gamma$ 需要包含所有可能被标记的符号的“带点”版本。
  2. 空列表或单元素列表:
  3. 输入 #:阶段1放左标记,阶段2找不到右标记,接受。正确。
  4. 输入 #01#:阶段1放左标记,阶段2找不到右标记,接受。正确。
  5. 算法的嵌套结构: 这个算法的控制流比前面的例子复杂得多,因为它是一个嵌套循环。在状态机层面,这意味着需要更多的状态来记住当前是处于外循环还是内循环,以及下一步是要移动左标记还是右标记。
📝 [总结]

示例3.12描述了一个解决元素互异性问题的图灵机 $M_4$。该算法通过巧妙地使用两个“移动标记”来模拟一个嵌套循环,系统地对输入列表中的所有字符串对 $(x_i, x_j)$ 进行两两比较。其核心比较步骤复用了前面例子中的“之字形”比较技术。这个例子展示了图灵机如何通过标记和复杂的控制流来处理结构化数据(如列表)并执行更复杂的组合算法。

🎯 [存在目的]

这个例子的目的是展示图灵机处理更高级别算法的能力。元素互异性是一个基础的计算问题,在数据库、数据分析等领域很常见。通过展示图灵机可以解决此问题,进一步巩固了丘奇-图灵论题的观点。同时,它引入了“移动标记”作为指针来管理嵌套循环的编程模式,这是图灵机算法设计中一个更有力的工具。

🧠 [直觉心智模型]

这就像你在一个班级里检查有没有重名的学生。

  1. 你有一个学生名单(磁带)。
  2. 你用一个红色夹子(左标记)夹住第一个学生的名字“张三”。
  3. 然后你用一个蓝色夹子(右标记)夹住第二个学生的名字“李四”。
  4. 你比较“张三”和“李四”,不一样。
  5. 你把蓝色夹子向下移动到第三个学生“王五”,比较“张三”和“王五”,不一样。
  6. ... 你把蓝色夹子移遍了“张三”后面的所有人。
  7. 现在,你把红色夹子从“张三”移到“李四”上。
  8. 然后你把蓝色夹子夹在“李四”后面的第一个人“王五”上,开始新一轮的比较。
  9. 这个过程一直持续,直到红色夹子移动到倒数第二个学生。如果在整个过程中你都没有发现重名,那你就确认全班没有重名。如果中途发现一对重名,你立刻就停下并报告。
💭 [直观想象]

你有一串用#隔开的珠子,每串珠子的颜色序列代表一个字符串。你要检查有没有两串珠子的颜色序列是完全一样的。

  1. 你用左手的食指(左标记)指向第一串珠子。
  2. 你用右手的食指(右标记)指向第二串珠子。
  3. 你仔细地比较这两串珠子,从头到尾,颜色是否一一对应。
  4. 检查完后,你保持左手不动,右手食指移到第三串珠子,再和左手指向的第一串比较。
  5. ... 右手移遍了所有珠子串后,你把左手食指移动到第二串珠子,然后右手从第三串开始,重复上述过程。

这个算法就是用你的两根手指作为指针,系统性地完成所有可能的两两对比。


  1. 对标记技术和结论的讨论

📜 [原文19]

这台机器说明了标记磁带符号的技术。在阶段 2 中,机器在符号(在本例中为 #)上方放置一个标记。在实际实现中,机器在其磁带字母表中有两个不同的符号:# 和 \#。机器在 # 上方放置标记意味着机器在该位置写入符号 \#。移除标记意味着机器写入没有点的符号。通常,我们可能希望在磁带上的各种符号上方放置标记。为此,我们只需在磁带字母表中包含所有这些符号的带有点的版本。

我们从前面的例子中得出结论,所描述的语言 $A, B, C$$E$可判定的。所有可判定语言都是图灵可识别的,因此这些语言也是图灵可识别的。证明一种语言是图灵可识别不可判定则更为困难。我们将在第 4 章中进行。

📖 [逐步解释]

这部分内容是对前面几个示例,特别是示例 3.12 中使用的技术的总结,并对这些示例所属的语言类别给出了结论。

  1. 标记磁带符号 (Marking Tape Symbols) 技术详解:
    • 概念: “在符号上方放置一个标记”是高层次描述中的说法。
    • 实际实现: 这并不是真的在符号“上方”做了什么,而是在图灵机的形式化模型中,通过扩展磁带字母表 $\Gamma$ 来实现的。
    • 方法:
  2. 假设我们想标记符号 s
  3. 我们在磁带字母表 $\Gamma$ 中引入一个全新的符号,比如 s_dot 或简写为
  4. “在 s 上放标记”这个动作,对应的图灵机操作就是:当磁头在 s 上时,执行一次写入操作,将 s 替换为
  5. “移除标记”的操作就是将 写回 s
  6. “检查标记”的操作就是让转移函数对 有特定的响应。
    • 通用化: 如果我们想能标记磁带上的任何符号(比如 a, b, c, #),我们只需要在 $\Gamma$ 中为它们都创建一个“带点”的版本:$\{a, b, c, \#, \dot{a}, \dot{b}, \dot{c}, \dot{\#}, ...\}$
    • 示例: 在 $M_4$ 中,为了标记 #,磁带字母表 $\Gamma$ 中需要同时包含 # 和一个新符号,比如 \#(带点的#)。
  7. 对示例语言的分类结论:
    • 语言:
    • $A = \{0^{2^n}\}$ (示例 3.7)
    • $B = \{w\#w\}$ (示例 3.9)
    • $C = \{a^i b^j c^k \mid i \times j = k\}$ (示例 3.11)
    • $E = \{\#x_1\#...\#x_l \mid x_i \neq x_j\}$ (示例 3.12)
    • 结论: 所有这些语言都是可判定的 (decidable)
    • 理由: 对于我们为这些语言设计的图灵机 ($M_2, M_1, M_3, M_4$),它们的算法对于任何输入,都能在有限的步骤内完成,并最终停机进入 q_acceptq_reject 状态。它们从不循环。因此,这些图灵机都是判决机 (deciders)。根据定义,如果一个语言能被一个判决机判决,那它就是可判定的。
  8. 重申语言类别的关系:
    • “所有可判定语言都是图灵可识别的”。这是一个重要的层级关系。
    • 理由: 判决机本身就是图灵机的一种特殊情况(行为更好的图灵机)。所以,如果一个语言是可判定的,就意味着存在一个判决机来判决它,而这个判决机也是一台图灵机,它识别这个语言。因此,该语言也必然是图灵可识别的。
  9. 预告后续内容:
    • 作者指出了下一个挑战:“证明一种语言是图灵可识别不可判定则更为困难。”
    • 这预示着我们将要遇到一类新的、更“奇怪”的问题,它们存在算法可以验证“是”的答案,但没有任何算法能保证对“不是”的答案给出回答(可能会永远算下去)。
    • 这个问题将在第4章中深入探讨,其核心就是著名的停机问题
∑ [公式拆解]

本段不含公式。

💡 [数值示例]
  • 标记技术的磁带字母表演示:
  • 假设要实现的算法需要标记 0, 1#
  • 输入字母表 $\Sigma = \{0, 1, \#\}$
  • 磁带字母表 $\Gamma$ 可能需要是:

$\Gamma = \{0, 1, \#, \sqcup, \dot{0}, \dot{1}, \dot{\#}\}$

  • 操作:
  • “标记0”: $\delta(q, 0) = (q', \dot{0}, R)$
  • “检查0是否被标记”: $\delta(q, \dot{0}) = (q', \dot{0}, L)$
  • “移除0的标记”: $\delta(q, \dot{0}) = (q', 0, R)$
⚠️ [易错点]
  1. 标记与状态: 标记是写在磁带上的,是图灵机的“外部记忆”。状态是控制器内部的,是“内部记忆”。两者经常协同工作。例如,一个状态可以是“我正在寻找一个带点的0”。
  2. 可判定 vs 可识别的再次强调: 这是本章最重要的概念之一,值得反复回味。可判定意味着问题“已解决”,总有算法能给出答案。可识别意味着问题“半解决”,我们只能确认是的答案。
  3. 为什么证明“可识别但不可判定”更难?:
  4. 要证明一个语言 L 是可识别的,我们只需要构造一台能识别它的图灵机 $M_L$ 即可。
  5. 要证明 L 是不可判定的,我们需要证明不存在任何判决机可以判决它。证明一个东西“不存在”通常比构造一个东西“存在”要困难得多,它需要更强大的数学工具,如对角线法。
📝 [总结]

本节总结了图灵机编程中的一个关键技术——通过扩展磁带字母表来实现“标记”,并明确了前面所有示例语言 ($A, B, C, E$) 都属于可判定语言的范畴。它重申了可判定语言图灵可识别语言的子集,并为下一章引入更复杂的“可识别但不可判定”的语言(如停机问题)埋下了伏"笔。

🎯 [存在目的]

这部分的目的是对 3.1 节进行收尾。它将前面分散的例子中出现的技术(标记)进行提炼和泛化,并从计算复杂性分类的角度对这些例子给予定位(它们都是可判定的)。这有助于读者形成一个关于图灵机能力和语言分类的初步框架,并激发对计算极限(即不可判定问题)的好奇心。

🧠 [直觉心智模型]
  1. 标记技术: 就像你在书上做笔记。你想强调一句话,就用荧光笔画它(写入带点符号)。你想记住某一页,就贴一张便利贴(写入特殊标记)。你的书(磁带)因此变得信息更丰富。
  2. 语言分类: 就像给数学问题分类。
  3. 可判定问题: 像“判断1357是否是质数”,总有一个确定的算法能在有限时间内给出“是”或“否”的答案。
  4. 可识别但不可判定问题: 像是“寻找一个偶数 $N > 2$,它不能被写成两个素数之和”(哥德巴赫猜想的反例)。你可以写个程序去一个一个试(2、4、6、8...),如果找到了,程序就停机并报告“找到了!”(接受)。但如果这样的数不存在,你的程序将永远运行下去(循环),你永远无法确定是没有还是没找到。
💭 [直观想象]

你是一名侦探。

  1. 可判定的案件: 证据就在那里,只要你按流程搜证、分析,总能在规定期限内结案,要么“定罪”,要么“无罪释放”。
  2. 可识别但不可判定的案件: 一个失踪人口案。你可以派人到处找,如果有一天找到了,皆大欢喜,案件了结(接受)。但如果一直找不到,你无法结案。你不知道这个人是已经死亡(可以被拒绝),还是只是躲在世界的某个角落你永远也找不到(循环)。你永远无法宣布“此人绝对不在地球上了”。

2行间公式索引

  1. $u a q_{i} b v \quad \text { 产生 } \quad u q_{j} a c v$

解释: 该公式形式化地定义了当图灵机执行一次“向左移动”的操作时,代表其瞬时状态的“格局”字符串如何变化。

  1. $u a q_{i} b v \quad \text { 产生 } \quad u a c q_{j} v$

解释: 该公式形式化地定义了当图灵机执行一次“向右移动”的操作时,代表其瞬时状态的“格局”字符串如何变化。

  1. $E=\left\{\# x_{1} \# x_{2} \# \cdots \# x_{l} \mid \text { 每个 } x_{i} \in\{0,1\}^{*} \text{ 且 } x_{i} \neq x_{j} \text{ 对于每个 } i \neq j\right\} 。$

解释: 该公式定义了“元素互异性”语言E,它由一列互不相同的二进制字符串组成,字符串之间由#分隔。

  1. 全章总结与展望
📝 [总结]

本章(3.1 图灵机)是计算理论的核心,它正式地引入了图灵机(Turing Machine)作为一种比有限自动机下推自动机更为强大的通用计算模型。本章首先通过非形式化的方式描述了图灵机的物理构成——一条可在其上进行读写的无限长磁带、一个可左右移动的磁头,以及一个拥有有限状态的控制器

接着,本章给出了图灵机严格的七元组形式化定义 $\left(Q, \Sigma, \Gamma, \delta, q_{0}, q_{\text {accept }}, q_{\text {reject }}\right)$,其中最关键的部分是转移函数 $\delta$,它精确地规定了机器在任何情况下应执行的“读-写-移动”操作。为了能够数学化地分析图灵机的计算过程,本章引入了“格局(Configuration)”这一至关重要的概念,它通过一个字符串 uqv 来捕捉机器在任意时刻的完整快照(当前状态、磁带内容、磁头位置)。基于格局,本章定义了单步计算——“产生(Yields)”关系,从而将整个计算过程描述为一个从起始格局开始的格局序列。

通过一系列难度递增的示例,本章展示了图灵机解决复杂问题的强大能力:

  1. $B=\{w\#w\}$:演示了“之字形”比较和“划掉”标记的基本技巧。
  2. $A=\{0^{2^n}\}$:演示了通过重复“减半”来进行算术性质的检查。
  3. $C=\{a^ib^jc^k | i \times j=k\}$:演示了通过嵌套循环和标记恢复来模拟乘法运算。
  4. $E=\{\#x_1\#... | x_i \neq x_j\}$:演示了通过移动标记作为“指针”来处理列表和执行两两比较的复杂算法。

最后,本章建立了计算理论中两个最核心的语言类别:

  1. 图灵可识别语言(Turing-recognizable):存在一台图灵机,对于语言中的任何字符串,它保证停机并接受;但对于不属于语言的字符串,它可能停机拒绝,也可能永不婷姬(循环)
  2. 图灵可判定语言(Turing-decidable):存在一台被称为“判决机(Decider)”的特殊图灵机,它对所有输入都保证在有限时间内停机,并给出明确的“接受”或“拒绝”的答案。

本章明确了所有可判定语言都是可识别的,并指出本章讨论的所有示例语言均为可判定的。章末通过预告“证明一种语言是图灵可识别但不可判定则更为困难”,为后续章节探讨计算的真正极限——以“停机问题”为代表的不可判定问题——埋下了关键的伏笔。

🎯 [存在目的]

本章的根本目的在于建立一个理论上的“计算”的黄金标准。通过定义图灵机,计算理论拥有了一个足以捕捉任何我们直觉中“算法”概念的数学模型,这就是著名的“丘奇-图灵论题”的核心思想。

本章的存在是为了:

  1. 定义计算的边界:通过图灵机这个统一的模型,我们可以开始精确地提问:什么是可计算的?什么是不可计算的?
  2. 建立问题难度等级:通过区分“可识别”与“可判定”,本章开始对问题的内在难度进行第一次划分,这是整个计算复杂性理论的基石。
  3. 提供分析工具:形式化定义、格局、产生关系等,为后续所有关于可计算性的严格证明提供了必不可少的数学语言和工具。
  4. 展示算法设计的本质:通过具体的图灵机示例,本章揭示了所有复杂的算法,无论在高层语言中看起来多么精妙,其本质都可以被分解为一系列极其简单的、机械的“读-写-移动”操作。
🧠 [直觉心智模型]

本章建立的图灵机心智模型是一个拥有无限草稿纸的、绝对遵守规则的机器人

  1. 无限草稿纸:即无限磁带,保证了机器的潜力不受内存大小的限制,只受算法本身的限制。
  2. 绝对遵守规则:即由转移函数 $\delta$ 定义的有限状态控制器。机器人没有任何创造力或直觉,它唯一的行为准则就是这本写死的规则手册。
  3. 计算过程:就是这个机器人在草稿纸上根据规则手册不断涂涂改改、来回查看的过程。
  4. 可判定 vs. 可识别:这个区别可以理解为机器人工作流程的区别。一个“可判定”的机器人,它的规则手册保证了它对任何初始草稿,总能在有限时间内完成工作并盖上“合格”或“不合格”的章。而一个“可识别”的机器人,它的规则手册只保证了对某些特定的稿件能最终盖上“合格”章,但对另一些稿件,它可能会陷入一个永远也完不成工作的涂改循环中。
💭 [直观想象]

想象你在为一个极其庞大的图书馆(拥有无限藏书)编纂一部完美的目录。你是一个图书管理员,但你只有一套非常简单的指令卡片。

  1. 图书馆的藏书和书架:就是无限磁带。
  2. 你(图书管理员)的位置和目光所及的书:就是磁头。
  3. 你的大脑状态(例如“我正在找科幻类”或“我正在核对ISBN号”):就是有限状态 $Q$
  4. 指令卡片($\delta$:上面写着:“如果你当前在想‘找科幻类’,并且看到了一本《三体》,那么,在书上贴一个蓝色标签,然后去看右边书架的下一本书。”
  5. 图灵机计算:就是你根据这套简单的指令卡片,在无穷无尽的书架间穿梭、贴标签、做记录的整个过程。
  6. 可判定性想象:一个“可判定”的任务是“检查这个书架上是否有两本完全一样的书”。你通过两两比较,总能完成任务并报告“有”或“没有”。一个“可识别但不可判定”的任务可能是“寻找一本记录了宇宙终极答案的书”。你可能永远在寻找的路上,无法停下来报告“找不到”,因为也许它就在下一个你还没检查过的书架上。本章告诉我们,即使拥有最简单的工具,只要有无限的时间和空间,你就能完成任何复杂的、有明确步骤的任务。

[[END_OF_RESPONSE]]所有解释内容已全部输出完毕。