LaTeX
LaTeX 有几个包可以用于排版“伪代码”形式的算法。这些包提供了比统一风格(例如,全部使用打字机字体)更多的样式增强,使得循环、条件等结构在视觉上与其他文本区分开来。伪代码通常放在算法环境中。对于排版真实代码,考虑使用 listings
包,具体内容见 "Source Code Listings"。
排版算法
有四个显著的包:algorithmic
、algorithm2e
、algorithmicx
和 program
。
使用 algorithmic
包排版
algorithmic
包使用与 algorithmicx
包不同的一组命令,并且与 revtex4-1 不兼容。基本命令如下:
\STATE <text>
\IF{<condition>} \STATE {<text>} \ELSE \STATE{<text>} \ENDIF
\IF{<condition>} \STATE {<text>} \ELSIF{<condition>} \STATE{<text>} \ENDIF
\FOR{<condition>} \STATE {<text>} \ENDFOR
\FOR{<condition> \TO <condition> } \STATE {<text>} \ENDFOR
\FORALL{<condition>} \STATE{<text>} \ENDFOR
\WHILE{<condition>} \STATE{<text>} \ENDWHILE
\REPEAT \STATE{<text>} \UNTIL{<condition>}
\LOOP \STATE{<text>} \ENDLOOP
\REQUIRE <text>
\ENSURE <text>
\RETURN <text>
\PRINT <text>
\COMMENT{<text>}
\AND, \OR, \XOR, \NOT, \TO, \TRUE, \FALSE
完整的文档可以在 [2] 中找到(链接已失效)。大多数命令与 algorithmicx
包中的命令类似,但有不同的大小写。CTAN 仓库中的算法包(日期为 2009-08-24)描述了算法环境(用于排版算法)和算法浮动包装器(参见下文),该包装器设计用于包裹算法环境。
algorithmic
包建议用于 IEEE 期刊,因为它是 IEEE 默认样式表的一部分。[1]
如何将 require
/ensure
重命名为 input
/output
:
\floatname{algorithm}{Procedure}
\renewcommand{\algorithmicrequire}{\textbf{Input:}}
\renewcommand{\algorithmicensure}{\textbf{Output:}}
使用 algorithm2e
包排版
algorithm2e
包(首次发布于 1995 年,最新更新版本为 2017 年 7 月的 v5.2 手册)允许对算法进行大量的自定义设置。与 algorithmic
包类似,该包也与 Revtex-4.1 不兼容。[2]
与 algorithmic
不同,algorithm2e
提供了大量的自定义选项,以适应不同用户的需求。CTAN 手册提供了一个详细的示例列表和完整的控制选项。
通常,使用 \begin{algorithm}
和 \end{algorithm}
之间的步骤如下:
-
声明一组关键字(用于排版为函数/运算符)、布局控制、标题、算法前的文本(如输入、输出)。
-
编写算法的主要步骤,每个步骤后使用
\;
结束。
这可以类比为编写 LaTeX 导言部分,然后开始实际文档。
加载此包的方法为:
\usepackage[]{algorithm2e}
以下是从 v4.01 手册中摘录的一个简单示例:
\begin{algorithm}[H]
\KwData{this text}
\KwResult{how to write algorithm with \LaTeX2e }
initialization\;
\While{not at end of this document}{
read current\;
\eIf{understand}{
go to next section\;
current section becomes this one\;
}{
go back to the beginning of current section\;
}
}
\caption{How to write algorithms}
\end{algorithm}
该代码会生成类似的结果。
有关更多细节,请查阅 CTAN 网站上的手册。
使用 algorithmicx
包排版
algorithmicx
包提供了许多常用的算法设计构造。要使用算法环境来编写伪代码(\begin{algorithmic}...\end{algorithmic}
),可以在导言部分加入 \usepackage{algpseudocode}
。你可能还想使用 algorithm
环境(\usepackage{algorithm}
)来将你的算法代码包裹在一个算法环境中(\begin{algorithm}...\end{algorithm}
),从而生成一个带有编号的浮动环境。
命令 \begin{algorithmic}
可以带有一个可选的正整数参数,若给定该参数,将会使行号按该整数的倍数进行编号。例如,\begin{algorithmic}[5]
会进入算法环境,并对每第五行进行编号。
以下是使用 algorithmicx
包排版一个基本算法的示例(记得在文档的导言部分添加 \usepackage{algpseudocode}
语句):
\begin{algorithmic}
\If {$i\geq maxval$}
\State $i\gets 0$
\Else
\If {$i+k\leq maxval$}
\State $i\gets i+k$
\EndIf
\EndIf
\end{algorithmic}
LaTeX 源代码可以用编程人员熟悉的格式书写,使得代码易于阅读。然而,这不会影响文档中的最终排版。
基本命令语法
-
语句(
\State
会引起换行,也可以用于其他命令之前):\State $x\gets <value>$
-
三种 if 语句:
\If{<condition>} <text> \EndIf \If{<condition>} <text> \Else <text> \EndIf \If{<condition>} <text> \ElsIf{<condition>} <text> \Else <text> \EndIf
第三种形式接受任意数量的
\ElsIf{}
子句。注意,它是\ElsIf
,而不是\ElseIf
。 -
循环:
\For{<condition>} <text> \EndFor \ForAll{<condition>} <text> \EndFor \While{<condition>} <text> \EndWhile \Repeat <text> \Until{<condition>} \Loop <text> \EndLoop
-
前置和后置条件:
\Require <text> \Ensure <text>
-
函数:
\Function{<name>}{<params>} <body> \EndFunction \Return <text> \Call{<name>}{<params>}
通常这个命令会与
\State
命令一起使用,示例如下:\Function{Increment}{$a$} \State $a \gets a+1$ \State \Return $a$ \EndFunction
-
注释:
\Comment{<text>}
注意:对于从旧的
algorithmic
包切换过来的用户,注释可以放在源代码的任何地方,不像旧的algorithmic
包那样有限制。
定义自定义环境
algorithmicx
包允许你定义自己的环境。
要定义一个以开始命令开始并以结束命令结束的块,使用:
\algblock[<block>]{<start>}{<end>}
这定义了两个命令 <start>
和 <end>
,它们没有参数。它们显示的文本是 \textbf{<start>}
和 \textbf{<end>}
。
通过 \algblockdefx
你可以指定开始和结束命令输出的文本,以及这些命令的参数数量。在文本中,第 n 个参数通过 #n
引用。
\algblockdefx[<block>]{<start>}{<end>}
[<startparamcount>][<default value>]{<start text>}
[<endparamcount>][<default value>]{<end text>}
示例:
\algblock[Name]{Start}{End}
\algblockdefx[NAME]{START}{END}%
[2][Unknown]{Start #1(#2)}%
{Ending}
\algblockdefx[NAME]{}{OTHEREND}%
[1]{Until (#1)}
\begin{algorithmic}
\Start
\Start
\START[One]{x}
\END
\START{0}
\OTHEREND{\texttt{True}}
\End
\Start
\End
\End
\end{algorithmic}
更多高级自定义和其他构造请参考 algorithmicx
手册:algorithmicx.pdf
使用 program
包排版
program
包提供了排版算法的宏。每一行都设置为数学模式,因此所有的缩进和间距都自动完成。|variable_name|
符号可以在普通文本、数学表达式或程序中用来表示变量名。使用 \origbar
可以在程序中显示正常的 |
符号。命令 \A
、\B
、\P
、\Q
、\R
、\S
、\T
和 \Z
会将相应的粗体字母与下一个对象作为下标进行排版(例如,\S1
会排版为 {\bf S$_1$} 等)。质数符号也可以正常使用,例如 \S‘‘
。
以下是使用 program
包排版一个基本算法的示例(记得在文档的导言部分添加 \usepackage{program}
语句):
\begin{program}
\mbox{A fast exponentiation procedure:}
\BEGIN \\ %
\FOR i:=1 \TO 10 \STEP 1 \DO
|expt|(2,i); \\ |newline|() \OD %
\rcomment{This text will be set flush to the right margin}
\WHERE
\PROC |expt|(x,n) \BODY
z:=1;
\DO \IF n=0 \THEN \EXIT \FI;
\DO \IF |odd|(n) \THEN \EXIT \FI;
\COMMENT{This is a comment statement};
n:=n/2; x:=x*x \OD;
\{ n>0 \};
n:=n-1; z:=z*x \OD;
|print|(z) \ENDPROC
\END
\end{program}
命令 \(
和 \)
minipage
中排版算法,因此算法可以作为公式中的一个单一框显示。例如,若要表示某个特定的动作系统等价于一个 WHILE 循环,可以写成:
\[
\( \ACTIONS A:
A \EQ \IF \B{} \THEN \S{}; \CALL A
\ELSE \CALL Z \FI \QE
\ENDACTIONS \)
\EQT
\( \WHILE \B{} \DO \S{} \OD \)
\]
Dijkstra 条件语句和循环:
\begin{program}
\IF x = 1 \AR y:=y+1
\BAR x = 2 \AR y:=y^2
\utdots
\BAR x = n \AR y:=\displaystyle\sum_{i=1}^n y_i \FI
\DO 2 \origbar x \AND x>0 \AR x:= x/2
\BAR \NOT 2 \origbar x \AR x:= \modbar{x+3} \OD
\end{program}
具有多个出口的循环:
\begin{program}
\DO \DO \IF \B1 \THEN \EXIT \FI;
\S1;
\IF \B2 \THEN \EXIT(2) \FI \OD;
\IF \B1 \THEN \EXIT \FI \OD
\end{program}
反向工程示例
这是原始程序:
\begin{program}
\VAR \seq{m := 0, p := 0, |last| := `` ''};
\ACTIONS |prog|:
|prog| \ACTIONEQ %
\seq{|line| := `` '', m := 0, i := 1};
\CALL |inhere| \ENDACTION
l \ACTIONEQ %
i := i+1;
\IF (i=(n+1)) \THEN \CALL |alldone| \FI ;
m := 1;
\IF |item|[i] \neq |last|
\THEN |write|(|line|); |line| := `` ''; m := 0;
\CALL |inhere| \FI ;
\CALL |more| \ENDACTION
|inhere| \ACTIONEQ %
p := |number|[i]; |line| := |item|[i];
|line| := |line| \concat `` '' \concat p;
\CALL |more| \ENDACTION
|more| \ACTIONEQ %
\IF (m=1) \THEN p := |number|[i];
|line| := |line| \concat ``, '' \concat p \FI ;
|last| := |item|[i];
\CALL l \ENDACTION
|alldone| \ACTIONEQ |write|(|line|); \CALL Z \ENDACTION \ENDACTIONS \END
\end{program}
这是转化和修正后的版本:
\begin{program}
\seq{|line| := `` '', i := 1};
\WHILE i \neq n+1 \DO
|line| := |item|[i] \concat `` '' \concat |number|[i];
i := i+1;
\WHILE i \neq n+1 \AND |item|[i] = |item|[i-1] \DO
|line| := |line| \concat ``, '' \concat |number|[i]);
i := i+1 \OD ;
|write|(|line|) \OD
\end{program}
该包还提供了一个宏,用于排版类似的集合:\set{x \in N | x > 0}
。
行号可以通过设置 \NumberProgramstrue
来启用,关闭行号则使用 \NumberProgramsfalse
。
包页面
包文档
算法环境(The algorithm environment)
在使用 algorithmic
排版的算法时,通常需要将算法“浮动”到文档中的最佳位置,以避免算法被拆分到多个页面。algorithm
环境提供了这一功能以及其他一些有用的功能。要在文档中使用该环境,请在导言部分添加:
\usepackage{algorithm}
使用方法如下:
\begin{algorithm}
\caption{<your caption for this algorithm>}
\label{<your label for references later in your document>}
\begin{algorithmic}
<algorithmic environment>
\end{algorithmic}
\end{algorithm}
算法编号(Algorithm numbering)
algorithm
包的默认编号系统是按顺序编号算法。这在大型文档中可能不太合适,尤其是当按章节编号更为恰当时。你可以通过提供应重新开始编号的文档部分的名称来影响算法的编号。此选项的合法值为:part
、chapter
、section
、subsection
、subsubsection
或空值(默认)。例如:
\usepackage[chapter]{algorithm}
算法列表(List of algorithms)
当你使用图形或表格时,可以在目录附近添加它们的列表;algorithm
包提供了一个类似的命令。只需在文档中的任意位置放置:
\listofalgorithms
LaTeX 将打印出文档中所有“algorithm”环境的列表,包含相应的页面和标题。
来自手册的示例(An example from the manual)
以下是从官方手册中提取的一个示例(官方手册,第14页):
\begin{algorithm} % 进入算法环境
\caption{Calculate $y = x^n$} % 给算法加上标题
\label{alg1} % 给算法添加标签,以便在文档后面使用 \ref{}
\begin{algorithmic} % 进入算法环境
\REQUIRE $n \geq 0 \vee x \neq 0$
\ENSURE $y = x^n$
\STATE $y \Leftarrow 1$
\IF{$n < 0$}
\STATE $X \Leftarrow 1 / x$
\STATE $N \Leftarrow -n$
\ELSE
\STATE $X \Leftarrow x$
\STATE $N \Leftarrow n$
\ENDIF
\WHILE{$N \neq 0$}
\IF{$N$ is even}
\STATE $X \Leftarrow X \times X$
\STATE $N \Leftarrow N / 2$
\ELSE[$N$ is odd]
\STATE $y \Leftarrow y \times X$
\STATE $N \Leftarrow N - 1$
\ENDIF
\ENDWHILE
\end{algorithmic}
\end{algorithm}
官方手册
官方手册位于:
http://mirrors.ctan.org/macros/latex/contrib/algorithms/algorithms.pdf
参考文献(References)
[1] Revtex4-1 和 algorithm2e 缩进冲突
算法包的官方手册,Rogério Brito (2009),算法手册