我在看这个问题,按行的字母顺序排列表格,并想,“那个 OP 需要某种冒泡排序器。”
我在这里做了一个数值冒泡排序器,使用 LaTeX 压缩数字列表(它实际上对参考编号进行了排序,并且压缩了连续的引用)并且发现我也做了一个 alpha-bubble 排序器,同样在这里,使用 LaTeX 对逗号分隔的列表进行排序?。
不幸的是,我发现当列表变大时,alpha-bubble 排序器很容易因递归而导致堆栈溢出。因此,我努力简化这里的事情,重写代码。它能够处理比引用版本更大的列表大小,但正如所包含的 MWE 所示,如果我取消注释列表中的那个额外项目(encontrar
),我就会破坏堆栈。
现在我知道,理论上,避免在条件递归期间炸毁堆栈的方法是...\expandafter\recursion\fi
。但是,当递归嵌套在块中很深时\if
,或者当递归不仅仅是一个宏名,而是一个...\recursion<data-block>\relax\fi
blob 时,我一直不擅长掌握这种技巧。
David C 告诉我堆栈大小是在 texmf.cnf 中设置的,尽管我还没有在我的 MikTeX 安装中找到该文件,但我意识到扩大堆栈并不是一个好的解决办法,而是一种更好的代码。
我还没有做出\the\lccode
调整来忽略搜索中的字母大小写,但是每次只能做一件事。
我认为通用的 LaTeX 阿尔法冒泡排序器不仅对我有用,而且对我之外的人也有用,因此我在这里将其作为一个问题发布,希望它能够被打败并成为一个有用的工具。
在下面的 MWE 中,例程\alphabubblesorter
调用\sortlist
进行主冒泡排序,\picknext
对于首字母相同的情况,调用 。因此,\sortlist
通过数据列表进行递归,\picknext
通过两个比较条目的字母列表进行递归。
\documentclass[10pt]{article}
\newcommand\alphabubblesort[1]{\def\sortedlist{}\expandafter\sortlist#1,9,\relax}
\def\sortlist#1#2,#3#4,#5\relax{%
\ifnum`#3=`9\relax%
\edef\sortedlist{\sortedlist#1#2}%
\else
\ifnum`#1<`#3\relax%
\edef\sortedlist{\sortedlist#1#2,}%
\sortlist#3#4,#5\relax%
\else%
\ifnum`#1>`#3\relax%
\let\tmp\sortedlist%
\def\sortedlist{}%
\expandafter\sortlist\tmp#3#4,#1#2,#5\relax%
\else%
\picknext#2!,#4!\relax%
\if F\flipflop%
\edef\sortedlist{\sortedlist#1#2,}%
\sortlist#3#4,#5\relax%
\else%
\let\tmp\sortedlist%
\def\sortedlist{}%
\expandafter\sortlist\tmp#3#4,#1#2,#5\relax%
\fi%
\fi%
\fi%
\fi%
}
\def\picknext#1#2,#3#4\relax{%
\ifnum`#1<`#3\relax
\xdef\flipflop{F}%
\else%
\ifnum`#1>`#3\relax%
\xdef\flipflop{T}%
\else%
\picknext#2!,#4!\relax%
\fi%
\fi%
}
\begin{document}
\alphabubblesort{da,cc,ca,eda,edc,edb,ef,ec,ed,eb,edzq,ba,e,fa,waaa,wa,qa}\sortedlist
\def\mydata{%
Spanish ,
ser ,
haber ,
estar ,
tener ,
hacer ,
poder ,
decir ,
ir ,
ver ,
dar ,
saber ,
querer ,
llegar ,
pasar ,
deber ,
poner ,
parecer ,
quedar ,
creer ,
hablar ,
llevar ,
dejar ,
seguir ,
%encontrar ,
llamar }
\alphabubblesort{\mydata}\sortedlist
\end{document}
答案1
类似这样的操作允许在递归调用之前弹出参数堆栈
\documentclass[10pt]{article}
\newcommand\alphabubblesort[1]{\def\sortedlist{}\expandafter\sortlist#1,zzzzzzzzzz,\relax}
\def\sortlist#1#2,#3#4,#5\relax{%
\let\next\relax
\ifnum`#3=`z\relax%
\edef\sortedlist{\sortedlist#1#2}%
\else
\ifnum`#1<`#3\relax%
\edef\sortedlist{\sortedlist#1#2,}%
\def\next{\sortlist#3#4,#5\relax}%
\else%
\ifnum`#1>`#3\relax%
\let\tmp\sortedlist%
\def\sortedlist{}%
\def\next{\expandafter\sortlist\tmp#3#4,#1#2,#5\relax}%
\else%
\picknext#2!,#4!\relax%
\if F\flipflop%
\edef\sortedlist{\sortedlist#1#2,}%
\def\next{\sortlist#3#4,#5\relax}%
\else%
\let\tmp\sortedlist%
\def\sortedlist{}%
\def\next{\expandafter\sortlist\tmp#3#4,#1#2,#5\relax}%
\fi%
\fi%
\fi%
\fi%
\next
}
\def\picknext#1#2,#3#4\relax{%
\ifnum`#1<`#3\relax
\xdef\flipflop{F}%
\else%
\ifnum`#1>`#3\relax%
\xdef\flipflop{T}%
\else%
\ZZfifi{\picknext#2!,#4!\relax}%
\fi%
\fi%
}
\def\ZZfifi#1\fi\fi{\fi\fi#1}
\begin{document}
\alphabubblesort{30,2c,2a,4da,4dc,4db,4f,4c,4d,2b,4dzq,10,4,50,W0,w0,q0}\sortedlist
\def\mydata{%
Spanish ,
ser ,
haber ,
estar ,
tener ,
hacer ,
poder ,
decir ,
ir ,
ver ,
dar ,
saber ,
querer ,
llegar ,
pasar ,
deber ,
poner ,
parecer ,
quedar ,
creer ,
hablar ,
llevar ,
dejar ,
seguir ,
encontrar ,
llamar }
\alphabubblesort{\mydata}\sortedlist
\end{document}
我不想干涉大卫(史蒂文)的惊人回答,但我意识到我可以通过直接转到来进一步简化事情\picknext
。我还添加了\the\lccode
筛选字母大小写的部分。
因此,在这个版本中,\sortlist
如果合适,仅执行两个相邻列表项的交换,而\picknext
决定是否应该进行交换。(\sortlist
除了列表结束条件之外,不再比较任何内容)。
由于 David 太谦虚了,没有列出他所做的更改的细节,我只想提醒读者注意他对 的使用\next
,这是一种将内容移出嵌套\if
结构的方法,并不罕见。但最精彩的是他创建并使用了\ZZfifi
,如果我理解得没错的话,它吸收了当前递归的剩余两个\fi
s,然后从堆栈中弹出其中两个作为下一个递归的第一步。大师级!
\documentclass[10pt]{article}
\newcommand\alphabubblesort[1]{\def\sortedlist{}\expandafter\sortlist#1,\cr,\relax}
\def\sortlist#1,#2,#3\relax{%
\let\next\relax
\ifx\cr#2\relax%
\edef\sortedlist{\sortedlist#1}%
\else
\picknext#1!,#2!\relax%
\if F\flipflop%
\edef\sortedlist{\sortedlist#1,}%
\def\next{\sortlist#2,#3\relax}%
\else%
\let\tmp\sortedlist%
\def\sortedlist{}%
\def\next{\expandafter\sortlist\tmp#2,#1,#3\relax}%
\fi%
\fi%
\next
}
\def\picknext#1#2,#3#4\relax{%
\ifnum\the\lccode`#1<\the\lccode`#3\relax
\xdef\flipflop{F}%
\else%
\ifnum\the\lccode`#1>\the\lccode`#3\relax%
\xdef\flipflop{T}%
\else%
\ZZfifi{\picknext#2!,#4!\relax}%
\fi%
\fi%
}
\def\ZZfifi#1\fi\fi{\fi\fi#1}
\begin{document}
\alphabubblesort{da,cc,ca,eda,edc,edb,ef,ec,ed,eb,edzq,ba,e,fa,waaa,wa,qa}\sortedlist
\def\mydata{
Spanish, ser, haber, estar, tener, hacer, poder, decir, ir, ver, dar, saber, querer,
llegar, pasar, deber, poner, parecer, quedar, creer, hablar, llevar, dejar,
seguir, encontrar, llamar}
\alphabubblesort{\mydata}\sortedlist
\end{document}