我正在尝试使用递归在 TikZ 中绘制谢尔宾斯基三角形。我有一些部分可以工作,但不是完全可以。在每个步骤中,我都会画一些东西。然后,如果计数器为正,我会再次调用我的宏。
这是一个稍微简化的例子,没有 TikZ 的内容(因为我很确定这不是我的问题所在):
\documentclass{article}
\newcounter{mycounter}
\newcommand{\example}[1]{%
\setcounter{mycounter}{#1}%
\themycounter%
\ifnum\themycounter>0%
[%
\setcounter{mycounter}{#1}%
\addtocounter{mycounter}{-1}%
\example\themycounter%
,%
\setcounter{mycounter}{#1}%
\addtocounter{mycounter}{-1}%
\example\themycounter%
]%
\fi%
}
\begin{document}
\example4
\end{document}
这是输出:
4[3[2[1[0,-1],-2],-3],3[2[1[0,-1],-2],-3]]
我想要的输出是:
4[3[2[1[0,0],1[0,0]],2[1[0,0],1[0,0]]],3[2[1[0,0],1[0,0]],2[1[0,0],1[0,0]]]]
我认为我的问题是\setcounter{mycounter}{#1}
扩展为\setcounter{mycounter}{\themycounter}
,这导致 的值没有变化mycounter
,而不是将其重置为宏开始时的值。有没有简单的解决方案?我需要学习如何\expandafter
工作吗?
答案1
如果问题出在计数器上,就移除计数器!:)
\documentclass{article}
\def\sierpinski#1{\number\expandafter\sierpaux\number\numexpr#1;}
\def\sierpaux#1;{%
\ifnum#1=0 0%
\else
\expandafter\sierpauxi\number
\expandafter\sierpaux\number\numexpr#1-1;;#1%
\fi}
\def\sierpauxi#1;#2\fi{\fi#2[#1,#1]}
\begin{document}
\sierpinski4
\edef\x{\sierpinski{19}}
\end{document}
代码是\sierpaux
宏的简单递归。循环开始时,它会向下遍历数字,减一,直到找到零,此时输入流如下所示:
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi 0;1\fi;2\fi;3\fi;4\fi
然后最后一个\sierpauxi
开始起作用并被替换0;1\fi
,\fi1[0,0]
然后\fi
展开,得到:
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi 1[0,0];2\fi;3\fi;4\fi
然后再次\sierpauxi
启动并替换1[0,0];2\fi
,2[1[0,0],1[0,0]]
重复此过程,直到剩下输出。请注意,它只计算一次数字列表,然后使用宏扩展根据需要复制所有内容,因此这是 O(n)。
但是列表很快就会变得很大,因此参数中可以拥有的最大数字是 19。
这是一个很多较慢的版本最多允许 20 个:
\documentclass{article}
\def\sierpinski#1{\sierpauxi{#1}}
\def\sierpauxi#1{\expandafter\sierpaux\number\numexpr#1;}
\def\sierpaux#1;{%
\ifnum#1=0 0%
\else #1\expandafter\sierpauxii\romannumeral-`0\sierpauxi{#1-1};%
\fi}
\def\sierpauxii#1;{[#1,#1]}
\begin{document}
\sierpinski4
\edef\x{\sierpinski{20}}
\end{document}
此版本以递归方式评估树的两侧,因此它是 O(n^2),但它会进行更多的调整,以便您可以获得更大的输入。
答案2
您的解释是正确的,但我认为在这里不使用计数器更简单,尤其是全局的乳胶计数器,并且使用\themycounter
打印形式,不能保证适合数字测试。
\documentclass{article}
\newcommand{\example}[1]{%
\the\numexpr#1\relax
\ifnum#1>0 %
[%
\expandafter\example\expandafter{\the\numexpr#1-1\relax}%
,%
\expandafter\example\expandafter{\the\numexpr#1-1\relax}%
]%
\fi%
}
\begin{document}
\example4
\end{document}
这只是直接传递值#1
而不使用寄存器