zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Latex 编写算法伪代码,基于algorithmicx包的使用说明(人工翻译自CTAN)

2023-04-18 16:08:50 时间

目录

摘要

其他布局的package

简介

算法块

简单的一行

注释

标签和引用

分解较长的算法

同一文档中使用多布局

结构化语法

for语句块

while循环

repeat语句

 if语句块

procedure语句块

function语句块

loop语句块

 输入输出语句

包选项 

给变量另起名字

示例

一份完整的伪代码

拆分算法的例子

 混合编排

References


前排提醒:

        有基础且自学很快的同学请跳转至示例结构化语法这两部分!


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完全兼容的包,但一般只用于“旧文档”??

简介

算法块

        每个算法以egin{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$
ightarrow$ #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命令通常用于标记所在行。当使用 ef命令对行进行引用时,它将用行号对原文进行代替。

        当algorithmicx包和algorithm包联合使用时,将能够同时标记和引用算法和所在行。algref命令可引用给定算法的某一行。

例子:

algref{<algorithm>}{<line>}

The 	extbf{while} in algorithm

ef{euclid} ends in line

ef{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>的语法段进行承接,它需要放在egin{algorithmic}[options]这一行的后面。

        algorithmicx还提供带*号的另一种版本:

algstore*{<savename>} 
...
algrestore*{<savename>} 

        与上面不带*有所不同,带星号的版本可选择是否恢复algrestore*之后的部分。一下子没看懂不用着急,示例中将对这部分进行展示。

同一文档中使用多布局

        我们能在同一文件中下载多种algorithmicx下的布局宏包。alglanguage{<layoutname>}命令能够实现不同布局之间的转换。在alglanguage{<layoutname>}之后,将开始启用<layoutname>这种语法的环境代替之前的语法环境。

结构化语法

        如果你对algorithmic package有一定了解的话,你会发现它们之间的转换非常简单。你可以使用旧的算法描述方式加上<algorithmic>布局, 新的算法描述则需要使用<algpseudocode>布局。下面以辗转相除法求解两数的最大公约数为例给出简单的算法模板:

egin{algorithm}
    caption{Euclid’s algorithm}label{euclid}
        egin{algorithmic}[1]
Procedure{Euclid}{$a,b$}Comment{The g.c.d. of a and b}
    State $rgets amod b$
While{$r
ot=0$}Comment{We have the answer if r is 0}
    State $agets b$
    State $bgets r$
    State $rgets amod b$
EndWhilelabel{euclidendwhile}
    State 	extbf{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

egin{algorithmic}[1]
    State $sumgets 0$
For{$igets 1, n$}
    State $sumgets sum+i$
EndFor
end{algorithmic}

while循环

While{<text>}
    <body>
EndWhile

egin{algorithmic}[1]
    State $sumgets 0$
    State $igets 1$
While{$ile n$}
    State $sumgets sum+i$
    State $igets i+1$
EndWhile
end{algorithmic}

repeat语句

Repeat
    <body>
Until{<text>}

egin{algorithmic}[1]
    State $sumgets 0$
    State $igets 1$
Repeat
    State $sumgets sum+i$
    State $igets i+1$
Until{$i>n$}
end{algorithmic}

 if语句块

        得仔细看哈:

If{<text>}
    <body>
[
  ElsIf{<text>}
    <body>
...
]
[
  Else
    <body>
]
EndIf

egin{algorithmic}[1]
If{$qualityge 9$}
    State $agets perfect$
ElsIf{$qualityge 7$}
    State $agets good$
ElsIf{$qualityge 5$}
    State $agets medium$
ElsIf{$qualityge 3$}
    State $agets bad$
Else
    State $agets 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}

egin{algorithmic}[1]
Require $xge5$
Ensure $xle-5$
    Statex
While{$x>-5$}
    State $xgets x-1$
EndWhile
end{algorithmic}

        此外,可用以下语句改写成input与output的形式:


enewcommand{algorithmicrequire}{	extbf{Input:}}  % Use Input in the format of Algorithm  

enewcommand{algorithmicensure}{	extbf{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>的形式存在。下面列出部分修改实例:

algrenewcommandalgorithmicwhile{	extbf{am’i g}}
algrenewcommandalgorithmicdo{	extbf{v’egezd el}}
algrenewcommandalgorithmicend{	extbf{v’ege}}
egin{algorithmic}[1]
    State $x gets 1$
While{$x < 10$}
    State $x gets x + 1$
EndWhile
end{algorithmic}

        在某些复杂的情况下,可能需要更多的自由更改的空间(比如上面的End与While需要对调,就是那两个看不懂的词)。有时候,命令所需要的参数可能也需要改变,这都可以通过自定义宏来完成。接下来展示一些常用的例子:

algrenewcommandalgorithmicwhile{	extbf{am’i g}}
algrenewcommandalgorithmicdo{	extbf{v’egezd el}}
algrenewcommandalgorithmicend{	extbf{v’ege}}
algrenewtext{EndWhile}{algorithmicwhile algorithmicend}
egin{algorithmic}[1]
    State $x gets 1$
While{$x < 10$}
    State $x gets x - 1$
EndWhile
end{algorithmic}

         调转了上面的End和While,得细心对比哦

algnewcommandalgorithmicto{	extbf{to}}
algrenewtext{For}[3]%
{algorithmicfor #1 gets #2 algorithmicto #3 algorithmicdo}
egin{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}
egin{document}
egin{algorithm}
caption{The Bellman-Kalaba algorithm}
egin{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 
ot= l’$
    State $l leftarrow l’$
Until{$
eg changed$}
EndProcedure
    Statex
Procedure {FindPathBK}{$v$, $u$, $p$}
If {$v = u$}
    State 	extbf{Write} $v$
Else
    State $w leftarrow v$
While {$w 
ot= u$}
    State 	extbf{Write} $w$
    State $w leftarrow p(w)$
EndWhile
EndIf
EndProcedure
end{algorithmic}
end{algorithm}
end{document}

拆分算法的例子

documentclass{article}
usepackage{algorithm}
usepackage{algpseudocode}
egin{document}
egin{algorithm}
caption{Part 1}
egin{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 betweendots

egin{algorithm}[h]
caption{Part 2}
egin{algorithmic}[1]
algrestore{bkbreak}
    State $p(i) leftarrow v_j$
EndIf
EndFor
    State $l’(i) leftarrow min$
EndFor
    State $changed leftarrow l 
ot= l’$
    State $l leftarrow l’$
Until{$
eg changed$}
EndProcedure
end{algorithmic}
end{algorithm}
end{document}

 混合编排

documentclass{article}
usepackage{algorithm}
usepackage{algpseudocode}
usepackage{algpascal}
egin{document}
alglanguage{pseudocode}
egin{algorithm}
caption{A small pseudocode}
egin{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}
egin{algorithm}
caption{The pascal version}
egin{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博客