澄清一下:当我说“图表”时,我的意思是计算机科学术语。
我想画一棵高度为的满二叉树h
。这意味着有一个根有两个儿子,每个儿子有两个儿子,依此类推。
有没有办法让 LaTeX(例如使用 tikZ,但任何其他方法都可以)绘制给定高度的完整二叉树,而h
无需手动绘制每个节点?这也应该允许我在边缘和叶子上书写。
谢谢。
答案1
这是我使用 TikZ 刚刚提出的一个公认的 hackish 解决方案:
\makeatletter
\def\bt@parent@index#1{\count0=#1\typeout{c01: \the\count0}\advance\count0 by -1\typeout{c02: \the\count0}\divide\count0 by 2\typeout{c03: \the\count0}\the\count0}
\newenvironment{binarytree}[1]{
\begingroup
\newcount\totaldepth\totaldepth=#1
\def\edge##1##2{\expandafter\edef\csname bt@edge##1\endcsname{##2}}
\def\leaf##1##2{\expandafter\edef\csname bt@leaf##1\endcsname{##2}}
}{
\newcount\rowlength % The number of nodes in the current generation of the tree
\rowlength=1
\newcount\numnodes\numnodes=0
\pgfmathparse{2^(\the\totaldepth)}
\newdimen\nodespread\nodespread=\pgfmathresult cm
%% Each node will be labeled as `node#', where # is its index. The nodes are indexed as if they were in an Ahnentafel list.
\newcount\parent
\begin{tikzpicture}
\foreach \depth in {1,...,\the\totaldepth} {
\foreach \i in {1,...,\the\rowlength} {
\pgfmathparse{(\the\numnodes - 1) / 2}
\parent=\pgfmathresult
\ifnum\parent=\numnodes
%% Special case for the root node of the tree
\node[fill,circle,inner sep=2pt] at (0,0) (node\the\numnodes) {};
\else\pgfmathparse{int(mod(\i,2))}\ifnum\pgfmathresult=1
%% This is the first node of a subtree's generation
\node[fill,circle,inner sep=2pt] at ([yshift=-1cm,xshift=-0.7\nodespread] node\the\parent) (node\the\numnodes) {};
\else
%% This is a node in the middle of a generation
\count0=\the\numnodes
\advance\count0 by -1
\node[right of=node\the\count0,right=\nodespread,fill,circle,inner sep=2pt] (node\the\numnodes) {};
\fi\fi
\ifnum\parent<\numnodes
%% Draw the edge to the parent
\draw (node\the\parent) -- node[sloped,above] {\csname bt@edge\the\numnodes\endcsname} (node\the\numnodes);
\fi
\ifnum\depth=\totaldepth
%% We are drawing a leaf, so see if it has a label
\node[below of=node\the\numnodes] (leaf\the\numnodes) {\csname bt@leaf\the\numnodes\endcsname};
\fi
\global\advance\numnodes by 1
}
\global\multiply\rowlength by 2
\global\nodespread=0.5\nodespread
}
\end{tikzpicture}
\endgroup
}
\makeatother
您必须稍微调整一下才能获得所需的节点间距。
只需将该代码粘贴到文档顶部(或新文档中.sty
)。然后你可以像这样使用它:
\begin{binarytree}{3} %% The "3" here is the depth of the tree
\edge{1}{First edge.}
\edge{5}{Edge 5.}
\leaf{3}{Leaf 1}
\leaf{4}{Leaf 2}
\leaf{5}{Leaf 3}
\end{binarytree}
边和叶子按照它们在树的相关人物列表。结果应该如下所示:
答案2
这更像是一个“概念验证”,而不是一个完全可行的例子;其要点如下。首先,展示如何使用循环递归地构建树\foreach
。其次,它使用了tree
TikZ 中已有的内容。第三,有人刚刚向我提到了 Htree在弄清楚如何绘制它时,我找到了问题的答案,我突然想到,只要稍加修改,绘制 H 树的程序就可以适应完整的二叉树。缺少的是标记功能,尽管我确信可以毫不费力地添加这些功能。
结果如下,首先是 H 树:
然后是二叉树:
现在代码是:
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\tikzset{
htree leaves/.initial=2,
sibling angle/.initial=20,
htree level/.initial={}
}
\def\htree@growth{%
\pgftransformrotate{%
(\pgfkeysvalueof{/tikz/sibling angle})*(-.5-.5*\tikznumberofchildren+\tikznumberofcurrentchild)}%
\pgftransformxshift{\the\tikzleveldistance}%
\pgfkeysvalueof{/tikz/htree level}%
}
\tikzstyle{htree}=[
growth function=\htree@growth,
sibling angle=180,
htree level={
\tikzleveldistance=.707\tikzleveldistance
\pgfsetlinewidth{.707*\the\pgflinewidth}
}
]
\tikzstyle{btree}=[
growth function=\htree@growth,
sibling angle=60,
htree level={
\tikzleveldistance=.55\tikzleveldistance
\pgfsetlinewidth{.707*\the\pgflinewidth}
}
]
\long\def\ge@addto@macro#1#2{%
\begingroup
\toks@\expandafter\expandafter\expandafter{\expandafter#1#2}%
\xdef#1{\the\toks@}%
\endgroup}
\newcommand{\htree}[2][]{%
\def\htree@start{\noexpand\coordinate}
\def\htree@end{}
\foreach \l in {0,...,#2} {
\g@addto@macro\htree@start{child foreach \noexpand\x in {1,2} {\iffalse}\fi}
\g@addto@macro\htree@end{\iffalse{\fi}}
\global\let\htree@start\htree@start
\global\let\htree@end\htree@end
}
\edef\htree@cmd{\htree@start\htree@end;}
\begin{scope}[htree,#1]
\htree@cmd
\end{scope}
}
\makeatother
\begin{document}
\begin{tikzpicture}[
rotate=-90,
yscale=.5
]
\htree[
btree,
level distance=3cm,
line width=8pt,
]{7}
\end{tikzpicture}
\end{document}
它通过构建适当的{child foreach \x in {1,2}
列表来工作。我们必须对分组有点狡猾(可能有更狡猾的方法)。其余的只是从trees
TikZ 中的库中修改而来。我在例程中添加了一个钩子,growth
这样就可以轻松地将每个级别的样式定义为“对以前样式的一些修改”,而不必专门为每个级别定义样式。使用不同的增长函数可能会产生更像 ESultanik 的答案中给出的示例的东西 - 这个答案的要点是使用循环构建树。
答案3
grahviz
您可以使用和的组合dot2tex
来生成漂亮的图表。这种组合可以生成漂亮的图表。
答案4
PGF/TikZ 的 CVS 存储库中正在开发一个用于自动(或我们在手册中称之为算法)图形绘制的新库。目前正在研究第一个严肃的图形绘制算法(包括基于力的算法、用于分层绘图(如流程图)的算法以及用于绘制树的算法)。
我不知道树算法的状态,但我们希望此功能(以及我提到的算法)能够在 2011 年某个时候随着新 PGF/TikZ 版本的发布而可用。