Latex 编写算法伪代码,基于algorithmicx包的使用说明(人工翻译自CTAN)
目录
前排提醒:
有基础且自学很快的同学请跳转至示例与结构化语法这两部分!
mlgb,搜了一圈没啥看一眼就能用的伪代码文章。有的故事将一大堆,有的各种环境或者语法问题。自己翻译一个以后还能照着看。
algorithmic 、algorithm2e与algorithmicx的故事渊源就不再介绍,文末references中可以了解(有一些不兼容的报错得注意)
本文主要参考官方说明文档编写而成,顺序有变动:(非机翻)CTAN: Package algoridicxhttps://ctan.org/pkg/algorithmicx
摘要
algorithmicx 包提供了许多定制的可能性算法布局。 我们可以使用其中一种预定义的布局如:pseudocode、pascal 和 c 等,可以自行修改,或者可以为特定的需求定义一个全新的布局。
使用方法:(本文以伪代码pseudocode的布局为例)
加入宏包
\usepackage{algorithm}
\usepackage{algorithmicx}
\usepackage{algpseudocode}
其他布局的package
algorithmicx 本身没有定义任何算法命令,但给出了一些宏来定义这样的命令集。 可以使用
algorithmicx定义自己的命令,或者使用其中一种预定义的命令集。
常用的预定义命令集:
\usepackage<algpseudocode>
\usepackage<algcompatible>
\usepackage<algpascal>
\usepackage<algc>
第一个是伪代码命令集,随后是类似于algorithmic的命令集,pascal语言和c语言的命令集。
第二个包的原文介绍是:it is fully compatible with the algorithmic package, it should
be used only in old documents.也就是与algorithmic完全兼容的包,但一般只用于“旧文档”??
简介
算法块
每个算法以\begin{algorithmic}[lines]命令开始,选项[lines]控制对行标号,1代表对每行进行标号,n代表为n,2n,3n行编号,直到\end{algorithmic}命令截至。
简单的一行
算法每行文本以\State开始,这与algorithmc包有所不同。需要指出的是,不需要在这个包的关键字前使用\State,因为这些命令会自动地启用一行。
特别地,如果需要启用不带标号的一行,也就是承接上一行,需要使用\Statex,它会跳入新的一行,且不对新行编号。
我们对以\State开始的行称为statements。对\Statex所在行的引用视为引用(\Statex)前一个statements所在的行号。
注释
注释以 \Comment命令开始,在algorithmicx包中,可以任意更改注释的样式,这一点不同于algorithmic包。例如改变\algorithmiccomment 宏定义:
\algrenewcommand{\algorithmiccomment}[1]{\hskip3em$\rightarrow$ #1}
会变成:
1: x ← x + 1 → Here is the new comment
这段语法我是不大懂的,猜测是将向左的箭头⬅改成了右箭头→。\hskip是用来创建水平空间的命令。
Tex命令可参考:
hskip - Tex命令 (vue5.com)http://www.vue5.com/tex_commands/hskip.html
标签和引用
\label命令通常用于标记所在行。当使用\ref命令对行进行引用时,它将用行号对原文进行代替。
当algorithmicx包和algorithm包联合使用时,将能够同时标记和引用算法和所在行。\algref命令可引用给定算法的某一行。
例子:
\algref{<algorithm>}{<line>}
The \textbf{while} in algorithm
\ref{euclid} ends in line
\ref{euclidendwhile}, so
\algref{euclid}{euclidendwhile}
is the line we seek.
样式结果:
The while in algorithm 1 ends in line 7,
so 1.7 is the line we seek.
分解较长的算法
有时候一段较长的算法需要被分成几部分描述,每一部分都是相对独立的存在(原文是separate float)。我们可以使用以下语法对algorithm进行拆分:
\algstore{<savename>}
...
\algrestore{<savename>}
上述语法通过自定义的savename保存算法原来的行号与所有标识。
其中,\algstore{<savename>} 语法使用在需要保存的算法末尾之前,即在\end{algorithmc}与\end{algorithm}之前。每段被保存的算法必须有着后续!
而后续的算法恰恰相反,\algrestore{<savename>}对具有相同<sabename>的语法段进行承接,它需要放在\begin{algorithmic}[options]这一行的后面。
algorithmicx还提供带*号的另一种版本:
\algstore*{<savename>}
...
\algrestore*{<savename>}
与上面不带*有所不同,带星号的版本可选择是否恢复\algrestore*之后的部分。一下子没看懂不用着急,示例中将对这部分进行展示。
同一文档中使用多布局
我们能在同一文件中下载多种algorithmicx下的布局宏包。\alglanguage{<layoutname>}命令能够实现不同布局之间的转换。在\alglanguage{<layoutname>}之后,将开始启用<layoutname>这种语法的环境代替之前的语法环境。
结构化语法
如果你对algorithmic package有一定了解的话,你会发现它们之间的转换非常简单。你可以使用旧的算法描述方式加上<algorithmic>布局, 新的算法描述则需要使用<algpseudocode>布局。下面以辗转相除法求解两数的最大公约数为例给出简单的算法模板:
\begin{algorithm}
\caption{Euclid’s algorithm}\label{euclid}
\begin{algorithmic}[1]
\Procedure{Euclid}{$a,b$}\Comment{The g.c.d. of a and b}
\State $r\gets a\bmod b$
\While{$r\not=0$}\Comment{We have the answer if r is 0}
\State $a\gets b$
\State $b\gets r$
\State $r\gets a\bmod b$
\EndWhile\label{euclidendwhile}
\State \textbf{return} $b$\Comment{The gcd is b}
\EndProcedure
\end{algorithmic}
\end{algorithm}
双栏下的效果:
\State在每句statement的开头,标志着新的一行的开始。\Procedure...\EndProcedure与\While...\EndWhile展示了绝大部分<algpseudocode>的语法规则。每段固定句式都有着开头与结尾,中继是正文,且关键字采用驼峰命名法。
在正确编排语法后,将自动根据缩进源进行缩进,但作者提醒大家规范的语法缩进有利于错误的查找。
突然来了一段我没太看懂的话:
In the case of syntax descriptions the text between < and > is symbolic,so if you type what you see on the left side, you will not get the algorithm on the right side. But if you replace the text between < > with a proper piece of algorithm, then you will probably get what you want. The parts between [ and ] are optional.
可能是想强调转义字符和原字符的输入区别?<>中间的内容原样显示。然后说[ ]中间是可选的options。
for语句块
for循环语句的几种样例如下:
\For{<text>}
<body>
\EndFor
\ForAll{<text>}
<body>
\EndFor
\begin{algorithmic}[1]
\State $sum\gets 0$
\For{$i\gets 1, n$}
\State $sum\gets sum+i$
\EndFor
\end{algorithmic}
while循环
\While{<text>}
<body>
\EndWhile
\begin{algorithmic}[1]
\State $sum\gets 0$
\State $i\gets 1$
\While{$i\le n$}
\State $sum\gets sum+i$
\State $i\gets i+1$
\EndWhile
\end{algorithmic}
repeat语句
\Repeat
<body>
\Until{<text>}
\begin{algorithmic}[1]
\State $sum\gets 0$
\State $i\gets 1$
\Repeat
\State $sum\gets sum+i$
\State $i\gets i+1$
\Until{$i>n$}
\end{algorithmic}
if语句块
得仔细看哈:
\If{<text>}
<body>
[
\ElsIf{<text>}
<body>
...
]
[
\Else
<body>
]
\EndIf
\begin{algorithmic}[1]
\If{$quality\ge 9$}
\State $a\gets perfect$
\ElsIf{$quality\ge 7$}
\State $a\gets good$
\ElsIf{$quality\ge 5$}
\State $a\gets medium$
\ElsIf{$quality\ge 3$}
\State $a\gets bad$
\Else
\State $a\gets unusable$
\EndIf
\end{algorithmic}
procedure语句块
\Procedure{<name>}{<params>}
<body>
\EndProcedure
function语句块
function语句块与上面的procedure类似:
\Function{<name>}{<params>}
<body>
\EndFunction
loop语句块
\Loop
<body>
\EndLoop
输入输出语句
算法的需求参数可以用 \Require 指令描述,结果可用\Ensure 指令描述。调用可用 \Call 指令。
\Require something
\Ensure something
\Statex
\State \Call{Create}{10}
\begin{algorithmic}[1]
\Require $x\ge5$
\Ensure $x\le-5$
\Statex
\While{$x>-5$}
\State $x\gets x-1$
\EndWhile
\end{algorithmic}
此外,可用以下语句改写成input与output的形式:
\renewcommand{\algorithmicrequire}{\textbf{Input:}} % Use Input in the format of Algorithm
\renewcommand{\algorithmicensure}{\textbf{Output:}} % Use Output in the format of Algorithm
包选项
<algpseudocode> package 支持以下选项:
compatible/noncompatible:
这个选项貌似被淘汰了,作者说如果你像使用旧的算法描述,请使用<algorithmic> package,然后使用<compatible>选项。这个选项定义了大写版本的命令,其实<algorithmic>与<algorithmicx>主要区别就是关键字的命名方法了,一个是全大写,一个是驼峰法。
此外,作者还提醒读者需要删除注释:[...],这大概是一些版本迭代和不兼容的原故吧。
noend/end:
默认选项为end,意思会显示所有的end。noend则意味着文中不会出现end,作者还提醒我们没有end可能会不好看。
有无end的比照:
网友还给出了去除如EndWhile这样单一end的方法,具体见文末第三篇参考。
给变量另起名字
不同的人可能使用到不同的伪代码语言,所以给伪代码中的关键字另起名字就变得很重要了。
在<algpseudocode>包中,所有的关键字都以\algorithmic<keyword>的形式存在。下面列出部分修改实例:
\algrenewcommand\algorithmicwhile{\textbf{am\’\i g}}
\algrenewcommand\algorithmicdo{\textbf{v\’egezd el}}
\algrenewcommand\algorithmicend{\textbf{v\’ege}}
\begin{algorithmic}[1]
\State $x \gets 1$
\While{$x < 10$}
\State $x \gets x + 1$
\EndWhile
\end{algorithmic}
在某些复杂的情况下,可能需要更多的自由更改的空间(比如上面的End与While需要对调,就是那两个看不懂的词)。有时候,命令所需要的参数可能也需要改变,这都可以通过自定义宏来完成。接下来展示一些常用的例子:
\algrenewcommand\algorithmicwhile{\textbf{am\’\i g}}
\algrenewcommand\algorithmicdo{\textbf{v\’egezd el}}
\algrenewcommand\algorithmicend{\textbf{v\’ege}}
\algrenewtext{EndWhile}{\algorithmicwhile\ \algorithmicend}
\begin{algorithmic}[1]
\State $x \gets 1$
\While{$x < 10$}
\State $x \gets x - 1$
\EndWhile
\end{algorithmic}
调转了上面的End和While,得细心对比哦
\algnewcommand\algorithmicto{\textbf{to}}
\algrenewtext{For}[3]%
{\algorithmicfor\ #1 \gets #2 \algorithmicto\ #3 \algorithmicdo}
\begin{algorithmic}[1]
\State $p \gets 1$
\For{i}{1}{n}
\State $p \gets p * i$
\EndFor
\end{algorithmic}
关于自定义命令的详细讲解留在下篇文章吧,这儿留个坑..文档在这个地方还介绍了pascal的算法伪代码,我就不翻译了。
示例
一份完整的伪代码
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\begin{document}
\begin{algorithm}
\caption{The Bellman-Kalaba algorithm}
\begin{algorithmic}[1]
\Procedure {BellmanKalaba}{$G$, $u$, $l$, $p$}
\ForAll {$v \in V(G)$}
\State $l(v) \leftarrow \infty$
\EndFor
\State $l(u) \leftarrow 0$
\Repeat
\For {$i \leftarrow 1, n$}
\State $min \leftarrow l(v_i)$
\For {$j \leftarrow 1, n$}
\If {$min > e(v_i, v_j) + l(v_j)$}
\State $min \leftarrow e(v_i, v_j) + l(v_j)$
\State $p(i) \leftarrow v_j$
\EndIf
\EndFor
\State $l’(i) \leftarrow min$
\EndFor
\State $changed \leftarrow l \not= l’$
\State $l \leftarrow l’$
\Until{$\neg changed$}
\EndProcedure
\Statex
\Procedure {FindPathBK}{$v$, $u$, $p$}
\If {$v = u$}
\State \textbf{Write} $v$
\Else
\State $w \leftarrow v$
\While {$w \not= u$}
\State \textbf{Write} $w$
\State $w \leftarrow p(w)$
\EndWhile
\EndIf
\EndProcedure
\end{algorithmic}
\end{algorithm}
\end{document}
拆分算法的例子
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\begin{document}
\begin{algorithm}
\caption{Part 1}
\begin{algorithmic}[1]
\Procedure {BellmanKalaba}{$G$, $u$, $l$, $p$}
\ForAll {$v \in V(G)$}
\State $l(v) \leftarrow \infty$
\EndFor
\State $l(u) \leftarrow 0$
\Repeat
\For {$i \leftarrow 1, n$}
\State $min \leftarrow l(v_i)$
\For {$j \leftarrow 1, n$}
\If {$min > e(v_i, v_j) + l(v_j)$}
\State $min \leftarrow e(v_i, v_j) + l(v_j)$
\State \Comment For some reason we need to break here!
\algstore{bkbreak}
\end{algorithmic}
\end{algorithm}
And we need to put some additional text between\dots
\begin{algorithm}[h]
\caption{Part 2}
\begin{algorithmic}[1]
\algrestore{bkbreak}
\State $p(i) \leftarrow v_j$
\EndIf
\EndFor
\State $l’(i) \leftarrow min$
\EndFor
\State $changed \leftarrow l \not= l’$
\State $l \leftarrow l’$
\Until{$\neg changed$}
\EndProcedure
\end{algorithmic}
\end{algorithm}
\end{document}
混合编排
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\usepackage{algpascal}
\begin{document}
\alglanguage{pseudocode}
\begin{algorithm}
\caption{A small pseudocode}
\begin{algorithmic}[1]
\State $s \gets 0$
\State $p \gets 0$
\For{$i \gets 1,\, 10$}
\State $s \gets s + i$
\State $p \gets p + s$
\EndFor
\end{algorithmic}
\end{algorithm}
\alglanguage{pascal}
\begin{algorithm}
\caption{The pascal version}
\begin{algorithmic}[1]
\State $s := 0$
\State $p := 0$
\For{i = 1}{10}
\Begin
\State $s := s + i$
\State $p := p + s$
\End
\end{algorithmic}
\end{algorithm}
\end{document}
References
latex 小白 algorithmic already defined的原因 - it610.com
LaTex伪代码手册 | algorithm2e、 algorithmicx、algorithmic - 知乎 (zhihu.com)
(176条消息) latex algpseudocode 不要 end 块 | noend | no end | without end_pineappleKID的博客-CSDN博客
更多推荐
所有评论(0)