算法 (algorithm2e/algpseudocode)

把代码放进稿件的方法不止一种。verbatim 按输入原样输出;listings / minted 用颜色和行号展示真实源代码;第三种方式则把与语言无关的过程放进编号为 “Algorithm 1” 的框中,也就是 伪代码。伪代码不同于真实代码,它会像图或表一样作为 *浮动体* 排在页面上,并带有 标题、连续编号、交叉引用和算法目录。本页聚焦于如何把伪代码作为一个 *可列出的对象* 放得体面,尤其是标题和编号。对同一批包的逐命令完整说明在 /learn/math/algorithms;这里给出两个生态的地图和各自的最小完整示例。

伪代码作为“浮动体”排版

verbatimlistings 把代码放在 正文流中,而伪代码通常放进 浮动体。浮动体是像 figure(图)或 table(表)一样,由 LaTeX 自动放到合适位置、避开尴尬分页的盒子。这样有两个好处。第一,有一个带连续编号的 “Algorithm 1” 标题,正文中可以用 \ref 引用。第二,长算法不会在页边界处被难看地截断;内层正文环境若直接放在正文中可能跨页断开,但浮动体盒子保持完整,并作为整体移到下一页。

第一个容易困惑的点,是有好几个名字相近的包。关键在于一种分工:一个包提供容器(带编号的浮动框),另一个包提供内容(伪代码本身)。不过这种分工只适用于两大流派中的一派。实际使用中,大体有两种选择。

  • 两层结构:algorithm(容器)+ algpseudocode(内容)。 algorithm 浮动体提供浮动框、标题和编号;algpseudocodealgorithmicx 的标准布局)提供伪代码正文,如 \State\For\If 等。
  • 一个包:algorithm2e 自成一体:它自带浮动体、标题和正文命令(\KwIn/\KwOut\eIf 等)。不要再加 algorithm(两者都会定义同名浮动环境,发生冲突)。

最重要的原则先说在前面:整个文档要统一选用其中一个流派algpseudocodealgorithm2e 在语法和理念上完全不同,同时加载会在 \For\If 等同名命令上冲突并报错。无论选择哪一个,都像平常一样编译两次,让编号、交叉引用和算法目录稳定下来。

标题、编号、引用与算法目录

本页的重点是作为掲載物的体裁。在任一流派中,\caption{…} 都会生成 “Algorithm N” 这样的标题,N 按出现顺序自动编号。紧接着放 \label{key},正文就能用 \ref{key} 取出这个编号,用 \pageref{key} 取出页码;做法与引用图表完全相同。

带编号浮动体的另一个好处是 算法目录。它类似 \listoffigures\listoftables;写下 \listofalgorithms 后,就会生成一个类似目录的列表,汇总各算法的编号和标题。列表中出现的是 \caption 给出的文字,在 algorithm 浮动体和 algorithm2e 下都一样有效。注意 algorithm2e 还提供与 \caption 不同、只加题名的 title 系命令,但它们不会向算法目录添加条目。

标题放置的 位置 随流派而不同。在 algorithm 浮动体中,和图一样,\caption 可以放在正文 前面或后面(很多人放在框的上方)。而在 algorithm2e 中,惯例是把 \caption 放在环境的 末尾,并且这个标题也会作为算法目录中的引用名。

流派 1:algorithm + algpseudocode

外层用 algorithm 浮动体包住,内层在 algorithmic 环境中写伪代码(包名是 algpseudocode,但环境名是 algorithmic)。正文命令都采用 首字母大写(如 \State\While),这也是与全大写旧 algorithmic\STATE)区分的方法。最常用的命令如下。

  • \State — 一条语句(一行)的开始;每条语句一个。
  • \For{…}\EndFor / \While{…}\EndWhile — 循环。
  • \If{…}\ElsIf{…}\Else\EndIf — 条件分支。
  • \Function{name}{args}\EndFunction,以及 \Return — 函数与返回值。
  • \Require / \Ensure — 前置条件和后置条件(带粗体标签)。
  • \Comment{…} — 行末注释。

开头的可选参数 [1] 控制行号:1 表示每行编号,n 表示每 n 行编号,省略则没有行号。下面是计算幂 y = xⁿ 的最小示例;注意 \label 放在 \caption 之后。

document.tex
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\begin{document}

\listofalgorithms

\begin{algorithm}
  \caption{Calculate $y = x^n$}\label{alg:power}
  \begin{algorithmic}[1]
    \Require $n \geq 0$
    \State $y \gets 1$
    \While{$n \neq 0$}
      \State $y \gets y \times x$
      \State $n \gets n - 1$ \Comment{count down}
    \EndWhile
    \State \Return $y$
  \end{algorithmic}
\end{algorithm}

アルゴリズム~\ref{alg:power} は累乗を計算する。

\end{document}

编译后,会得到一个上下带横线、在页面上浮动的框,顶部标题为 “Algorithm 1 Calculate y = xⁿ”(编号自动生成)。每行左侧会有 1, 2, 3 … 的行号,正文中的 \ref{alg:power} 会解析为该编号(这里是 1)。开头的 \listofalgorithms 会生成类似 “1 Calculate y = xⁿ … page” 的条目。关于每个命令的输出,包括 \ElsIf\Function,请参见 /learn/math/algorithms

流派 2:algorithm2e

algorithm2e 是另一个体系,把容器和内容 自成一体地放在一个包中(当前版本 5.2,2017 年)。在 \begin{document} 之前用 \usepackage[…]{algorithm2e} 加载;它的 algorithm 环境本身就是浮动体。外观通过加载选项选择:ruled(上下横线)、boxed(整体加框)、vlined/lined(块结构竖线)、plain(默认,无装饰);加 linesnumbered 则显示行号。语法要点有三条:

  • 输入/输出使用专用命令 \KwIn{…}/\KwOut{…}(或 \KwData{…}/\KwResult{…}),输出为粗体 “Input:”、“Output:” 等。
  • 分支和循环把正文作为花括号参数传入。 if–then–else 写作 \eIf{cond}{then}{else};循环写作 \For{…}{body}\While{…}{body}(用 \KwTo 表示 “to”)。
  • 每条语句以 \\; 结尾(反斜杠加分号)。忘记它,下一条语句会接在同一行。若不想在输出中显示 “;”,使用 \DontPrintSemicolon
document.tex
\documentclass{article}
\usepackage[ruled,linesnumbered]{algorithm2e}
\begin{document}

\listofalgorithms

\begin{algorithm}
  \caption{Sum of positive entries}\label{alg:sum}
  \KwIn{an array $a[1..n]$}
  \KwOut{the sum $s$ of its positive entries}
  $s \gets 0$\;
  \For{$i \gets 1$ \KwTo $n$}{
    \eIf{$a[i] > 0$}{
      $s \gets s + a[i]$\;
    }{
      skip\;
    }
  }
  \Return $s$\;
\end{algorithm}

アルゴリズム~\ref{alg:sum} は正の要素を合計する。

\end{document}

ruled 选项在上下画横线并在顶部放标题行,linesnumbered 给每行编号。框开头有粗体 “Input:” 和 “Output:”;\For 行排成 for i ← 1 to n do,正文缩进;\eIfifthen 的真分支放在 else 的假分支上方。每个 \; 处发生换行,最后一行是 return s。\caption 文字会原样出现在 \listofalgorithms 中。更细的控制,如 [H](固定在当前位置不浮动)、\SetAlgoLined(给块画竖线)等,详见 /learn/math/algorithms

该用哪一个

两者都被广泛使用,差别更多是风格而不是优劣。可以用下面的速查表先判断方向。

角度algorithm + algpseudocodealgorithm2e
構成两层,两个包一个自成一体的包
本体の書き方\State 开头的直接命令体系块正文作为花括号参数传入
入出力\Require / \Ensure\KwIn / \KwOut(显式)
行末不需要必须有 \\;
向く人想要传统外观;模板默认采用它重用显式输入输出、竖线、多语言关键字

无论哪一派,作为掲載物的处理方式相同:用 \caption 给出带编号标题,用 \label/\ref 引用,用 \listofalgorithms 生成列表。再强调一次:正文包只选一个;如果使用 algorithm2e,不要加载容器包 algorithm。完整命令列表和更长的示例请见 /learn/math/algorithms。如果想展示带颜色和行号的真实源代码(不是伪代码),则应使用 /learn/code-verbatim/code-listings 中的 listings/minted