2026/10/2 15:14:42

LaTeX论文排版实战:伪代码与代码块的高效写法

LaTeX论文排版实战:伪代码与代码块的高效写法 写论文最头疼的事情之一就是算法伪代码和代码块怎么排版。用Word排版过算法的人应该都有体会缩进对不齐、行号乱了、代码高亮一塌糊涂光是调整格式就能耗掉一下午。转用LaTeX之后才发现这些事情其实有非常成熟的解决方案。这篇笔记就专门聊聊LaTeX里的伪代码和代码块到底怎么写从宏包选型到实际配置再到我踩过的各种坑一次性讲清楚。1. 先把环境准备好伪代码和代码块的运行前提1.1 编译器与宏包选择先说明一点伪代码和代码块的排版并不需要什么特殊的编译器常规的pdfLaTeX、XeLaTeX都能跑。但如果你要往代码块里写中文注释或者伪代码里本身就要用到中文字符那建议直接用XeLaTeX搭配ctex宏包省去一堆字体配置的麻烦。我目前用的是TeX Live安装的时候直接全量安装虽然占了几个G的硬盘但好处是宏包基本齐全不用临时缺什么再补装什么。这里顺便提一下安装。很多新手卡在第一步其实LaTeX发行版就选两个主流TeX Live跨平台更新快和MiKTeXWindows下体验不错按需自动安装宏包。我个人的建议是直接用TeX Live因为写论文经常要投不同期刊的模板TeX Live对各类宏包的支持更完整编译兼容性也更好。安装完记得在终端里跑一下latex -v看到版本信息就说明环境已经通了。1.2 在VSCode里快速搭建编写环境编辑器我用的是VSCode配合LaTeX Workshop插件体验非常接近IDE。装好插件之后还需要做两件事第一确认插件能自动识别你的TeX发行版LaTeX Workshop默认会去系统PATH里找latexmk只要你安装了TeX Live并加入了PATH一般就能直接编译第二配置编译工具链在settings.json里加上这么一段{ latex-workshop.latex.recipes: [{ name: xelatex, tools: [xelatex] }], latex-workshop.latex.tools: [{ name: xelatex, command: xelatex, args: [ -synctex1, -interactionnonstopmode, -file-line-error, %DOC% ] }] }用XeLaTeX作为默认编译器主要是为了上面的中文支持和字体处理。VSCode配上LaTeX Workshop之后保存自动编译、PDF预览、SyncTeX正反向定位都齐了写伪代码和代码块的时候编译反馈是即时的定位报错也很方便。个人建议开-interactionnonstopmode这样遇到错误不会停下来等你输入指令而是直接往下跑最后统一看日志对新手来说更友好。2. 伪代码方案选型algorithm、algorithmic与algpseudocode怎么选2.1 三种主流宏包的定位与区别LaTeX里写伪代码绕不开几个经典的宏包组合。很多新手一上来就被algorithm、algorithmic、algorithmicx、algpseudocode、algpascal这些名字搞混了。我花过一段时间把它们的区别理清楚了其实没那么复杂。algorithm宏包是一个浮动体包装器它提供一个类似于table、figure的算法环境用来给算法加编号、加标题\caption、生成目录条目。真正管算法内部排版的是另外一个宏包。algorithmic宏包是最老的算法排版工具命令风格是\IF、\FOR、\REPEAT这种全大写、带反斜杠的写法语法接近原始的算法描述语言但灵活性差一些缩进和块结构控制不够精细。algorithmicx以及它衍生出的algpseudocode、algpascal、algc等是改进版本核心是algpseudocode提供的语法命令变成了\If、\For、\While这样首字母大写的形式块结构用\EndIf、\EndFor来关闭配合\State逐行写语句。整体写起来更像是在写伪代码本身而不是在被宏包的语法折腾。所以我的选型结论是直接用algorithm加algpseudocode这个组合也就是algorithm做浮动体外壳algpseudocode负责内部排版。这也是目前期刊论文里最常见的搭配。2.2 按行号、缩进与控制流algpseudocode的具体写法经历过几种宏包的对比之后我把实际写论文经常用到的模板总结了一下。需要在导言区引入这几个宏包\usepackage{algorithm} \usepackage{algpseudocode}一个标准算法的写法是下面这样的\begin{algorithm} \caption{基于贪心策略的资源调度算法} \label{alg:greedy} \begin{algorithmic}[1] \Require 任务集合 $T$资源集合 $R$ \Ensure 调度方案 $S$ \State 初始化 $S \leftarrow \emptyset$ \For{每个任务 $t \in T$} \State 按优先级从高到低排序候选资源 \For{每个候选资源 $r \in R$} \If{$r$ 满足 $t$ 的约束条件} \State 将 $t$ 分配给 $r$ \State $S \leftarrow S \cup \{(t, r)\}$ \State \textbf{break} \EndIf \EndFor \EndFor \State \Return $S$ \end{algorithmic} \end{algorithm}有两个细节值得展开。第一\begin{algorithmic}[1]里的参数[1]表示按行编号而且编号的粒度是每一行语句如果不传参数默认不显示行号。有些模板要求算法行号连续编号有些要求按算法独立编号这取决于期刊的要求用[1]一般是最稳妥的。第二\State是algpseudocode的基石命令不管是一条赋值语句、一个函数调用还是一句注释基本都要用\State开头。控制流语句\If、\For、\While、\Repeat、\Function会自动调整缩进和块结构你只需要正确地闭合它们。比如\If对应\EndIf\For对应\EndFor\Function对应\EndFunction。如果漏掉了一个\EndIf编译报错会指向整个algorithmic环境而不是精确到某一行这个排错路径我在后面第4部分细讲。2.3 函数、输入输出与跨栏问题的处理写伪代码的时候函数定义和输入输出是很常见的需求。algpseudocode提供了一组直接可用的命令\begin{algorithmic}[1] \Function{MinCost}{$G$, $s$} \State $dist \leftarrow \infty$ \Comment{初始化距离数组} \For{$v$ in $G.vertices$} \State $dist[v] \leftarrow \infty$ \EndFor \State $dist[s] \leftarrow 0$ \State $Q \leftarrow G.vertices$ \While{$Q \neq \emptyset$} \State $u \leftarrow$ ExtractMin($Q$) \For{each neighbor $v$ of $u$} \If{$dist[u] w(u,v) dist[v]$} \State $dist[v] \leftarrow dist[u] w(u,v)$ \EndIf \EndFor \EndWhile \State \Return $dist$ \EndFunction \end{algorithmic}\Function自动处理函数名和参数的排版\Comment可以加行内注释\Require和\Ensure则分别对应算法开始前的输入、输出说明也就是类似Require: xxx / Ensure: xxx的那两行。这套语法基本覆盖了论文里90%的算法描述场景。另外一个常见需求是跨栏问题。如果你在用双栏模板写论文某个伪代码太长单栏放不下但你又不想让它被截断可以给algorithm环境加上*号变成\begin{algorithm*}这样它就会横跨两栏。不过跨栏算法的位置浮动行为会比较难控制有时候会跑到下一页的顶部建议配合t位置参数使用\begin{algorithm*}[t]尽量让它出现在当前页顶部。还有一点关于标题的细节。用\caption{}管理算法标题之后默认会显示Algorithm 1: 标题的形式。如果你的期刊要求显示成算法1需要额外配置常见的写法是在导言区加上\renewcommand{\algorithmcfname}{算法}或者根据你用的具体宏包版本做相应的\floatname设置。这类细节往往决定了投稿时能不能通过格式审查很值得提前处理。3. 代码块排版实战listings与minted3.1 listings宏包的通用配置思路伪代码解决之后代码块又是另一块硬骨头。LaTeX里展示代码块有两个主流方案listings和minted。listings的优势是完全依赖LaTeX本身不需要额外的外部工具兼容性最好minted依靠Python的Pygments库做语法高亮颜色和样式更精致但编译时必须要加-shell-escape参数否则会报错。我平时写博客、做技术笔记用的是listings因为环境简单、不容易出幺蛾子。先用一个案例说明基本配置把下面这段放在导言区\usepackage{listings} \usepackage{xcolor} \lstdefinestyle{mycode}{ languagePython, basicstyle\ttfamily\small, keywordstyle\color{blue}, commentstyle\color{gray}, stringstyle\color{red}, numbersleft, numberstyle\tiny\color{gray}, framesingle, rulecolor\color{black}, breaklinestrue, showstringspacesfalse, tabsize4, captionposb } \lstset{stylemycode}这样定义好样式之后正文里用\begin{lstlisting}[languagePython, caption示例代码] def hello(): print(Hello, LaTeX!) \end{lstlisting}简单解释一下几个关键参数。basicstyle控制代码字体一般用等宽的\ttfamilykeywordstyle、commentstyle、stringstyle分别设置关键字、注释、字符串的颜色breaklinestrue允许自动断行这是处理长代码行的救命配置showstringspacesfalse避免字符串里的空格显示成特殊符号。语言类型可以根据需要改listings支持的语言相当多常见的Python、Java、C/C、Matlab、R、SQL都在支持列表里。3.2 让代码块支持中文与特殊符号listings有个很经典的坑默认情况下lstlisting环境里的中文注释会编译成乱码或者直接报错。如果你用的是XeLaTeX编译解决办法比较直接给\lstset加上\lstset{ extendedcharstrue, inputencodingutf8 }但更稳妥的方式是设置literate选项手动告诉listings如何显示中文。我常用的配置是这样\lstset{ literate{中文}{{中文}}1 {注释}{{注释}}1 {代码}{{代码}}1 }这种方式适合中文注释只出现在少数固定的词里。如果代码里中文注释太多、内容不固定我建议干脆换minted或者把中文注释改成英文。说实话期刊论文的代码块注释通常不会太长英文注释是最省事的方案。还有一个经常遇到的问题listings环境和文本之间的空格。默认情况下\begin{lstlisting}前面有没有缩进、后面有没有空行会直接影响代码块的显示位置。如果不小心在\end{lstlisting}后面留了空格版面上会出现多余的空隙。我在自己的笔记里总结的规则是lstlisting环境前后都保持顶格写不要缩进这样最不容易出问题。3.3 跨页、断行与高亮几个救命配置写技术文档的时候一段完整的代码往往会超过一页listings默认会直接截断但截断的位置没有提示看起来很难受。这时可以加个frame配合跨页处理或者用特殊的省略标记。我常用的做法是\lstset{ breaklinestrue, prebreak\raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}}, postbreak\raisebox{0ex}[0ex][0ex]{\ensuremath{\hookrightarrow}}, breakatwhitespacefalse }这样长代码在断行处会显示一个向左或向右的箭头读者一看就知道这一行还没结束。breakatwhitespacefalse的意思是允许在任意字符处断行而不仅仅是空格位置。如果你用minted跨页问题有另外一个思路。minted本身不支持直接分页通常要配合tcolorbox使用。我也试过几次这个组合的效果确实漂亮能做出带背景色、圆角边框的代码块但配置相对复杂还需要确保系统装了Python环境和Pygments库。判断标准很直接本地写给自己看的笔记listings完全够用要做成演示文档或者课程材料再考虑上minted。4. 常见问题与排查技巧实录4.1 编译报错“Environment algorithm undefined”之类怎么办这个报错是典型的宏包缺失。algorithm环境在algorithm宏包里算法内部的排版指令在algpseudocode宏包里。你只用了algpseudocode却不引入algorithm就会出现Environment algorithm undefined。解决办法就是在导言区同时引入这两个。还有一种情况是你用了\usepackage{algorithmic}而不是\usepackage{algpseudocode}那么\If、\For这些命令都识别不了因为老版algorithmic宏包用的是全大写的\IF、\FOR。所以遇到报错先别慌看一眼宏包名是不是搞混了。4.2 换行符、空格、特殊字符的那些坑LaTeX文章主体里空行控制段落间距输入多个空格会被压缩成一个空格。但在lstlisting环境内部所有空格和换行都会原样保留这是代码块排版区别于普通正文的最大特点。如果你发现代码块里的缩进消失了检查一下是不是用了listings但没设置tabsize或者代码里用了Tab而listings默认不识别Tab宽度。我一般统一设置tabsize4并且代码文件里全部用空格代替Tab这样在LaTeX和其他编辑器之间切换都不会乱。伪代码环境里则相反\State后面的语句里如果要显示多条语句或特殊符号需要自己控制分隔。比如表示赋值建议用\leftarrow而不是直接打一个等号这样类别更清晰等于判断则用。不要混淆这两个符号的语义。还有%在LaTeX里是注释符想在伪代码或代码里显示百分号必须写成\%。我第一次写带百分号的伪代码时编译通过但后面的内容全消失了找了好久才发现是%惹的祸。4.3 特殊字符与符号映射的快捷参考这里把常见字符在LaTeX里的正确写法直接列出来省得每次都去查。表格可以当速查手册用显示效果LaTeX写法适用环境赋值箭头$\leftarrow$伪代码返回箭头$\rightarrow$伪代码小于等于$\leq$伪代码/数学不等于$\neq$伪代码/数学百分号\%全部井号\#全部下划线\_全部花括号\{\}全部反斜杠\textbackslash代码块/文本波浪线\textasciitilde代码块/文本这个表格是我自己整理网上宏包符号教程时精简出来的基本覆盖了写算法和代码块时最常用的一批特殊字符。出现符号无法显示的问题时先查这个表。4.4 个人踩坑记录从报错到稳定出图的排查顺序我刚开始用LaTeX排伪代码的时候遇到一个特别奇怪的现象algorithm环境里明明写了\caption{xxx}但生成的PDF里标题显示成Algorithm 1: xxx而不是我自己写的文字。查了半天才发现是模板引入了一个algorithm2e宏包它和algorithm宏包的命令冲突导致\caption格式化被覆盖了。解决方法是二选一只保留一套宏包体系。后来我干脆在写论文模板适配时先翻一下主模板的宏包列表再决定用哪个方案。踩过的另一个坑是algpseudocode的\Function命令在函数名带数字下标时有时候会编译报错。原因在于函数名里的下划线被当成了数学下标标记。正确的做法是把函数名用\text包一层比如\Function{Min\_Cost}{}要写成\Function{\text{Min\_Cost}}{}。这个坑特别隐蔽因为单看代码很容易忽略。排查编译问题的时候我习惯按这样的顺序来先看VSCode的LaTeX Workshop输出窗口里的错误日志找出第一个Error然后检查对应的宏包是否存在、是否冲突再看是不是特殊字符没有转义。大多数问题都在这三步里就能定位。如果日志看不懂我会把文档拆成最小例子只留一个伪代码或一个代码块一段段往上加加一次编译一次直到复现报错位置。这个方法虽然笨但在排查宏包冲突时特别管用。4.5 重要提示浮动体与文字错位问题最后一个常见问题不是报错而是排版不理想。algorithm环境是浮动体跟你用table、figure一样它会被LaTeX自动挪到页面的某个位置不保证出现在源码编辑位置的正下方。如果你看到这里留了一大片空白算法跑到下一页去了别急着怀疑代码先调整位置参数改成\begin{algorithm}[htbp]让LaTeX有更多选择余地。如果还是不满意可以用[H]强制放在当前位置但需要额外引入float宏包\usepackage{float} ... \begin{algorithm}[H] ... \end{algorithm}我用[H]的时候比较克制因为它会牺牲一些排版美感但对论文初稿的审阅阶段很实用毕竟先看到完整内容比纠结位置更重要。5. 从笔记到项目一次完整的练习说了这么多光看不如动手。我建议你新建一个测试文档把伪代码、代码块、跨栏算法、断行配置全部放进去编译一遍。我自己的练习模板大概是这样的给你做个参考\documentclass[11pt]{article} \usepackage[UTF8]{ctex} \usepackage{algorithm} \usepackage{algpseudocode} \usepackage{listings} \usepackage{xcolor} \usepackage{float} \lstset{ languagePython, basicstyle\ttfamily\footnotesize, breaklinestrue, showstringspacesfalse, tabsize4 } \begin{document} \section{伪代码示例} \begin{algorithm}[H] \caption{快速排序} \label{alg:quicksort} \begin{algorithmic}[1] \Function{QuickSort}{$A, low, high$} \If{$low high$} \State $p \leftarrow \text{Partition}(A, low, high)$ \State \Call{QuickSort}{$A, low, p-1$} \State \Call{QuickSort}{$A, p1, high$} \EndIf \EndFunction \end{algorithmic} \end{algorithm} \section{代码块示例} \begin{lstlisting}[captionPython示例] def quick_sort(arr): if len(arr) 1: return arr pivot arr[len(arr) // 2] left [x for x in arr if x pivot] middle [x for x in arr if x pivot] right [x for x in arr if x pivot] return quick_sort(left) middle quick_sort(right) \end{lstlisting} \end{document}这个文档直接保存成.tex用XeLaTeX编译一次就能通过。如果你在编译过程中遇到了任何一条本文提到的报错再回头看对应的章节基本上都能找到解决方案。我个人在实际操作中的体会是LaTeX的伪代码和代码块排版真正的难点从来不是宏包不够用而是宏包选型不统一、符号转义漏掉、浮动体位置控制不好这三个老问题。把这三关过了剩下的都是熟能生巧。