如何在 LaTeX 中自动绘制图形

如何在 LaTeX 中自动绘制图形

澄清一下:当我说“图表”时,我的意思是计算机科学术语

我想画一棵高度为的满二叉树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。​​其次,它使用了treeTikZ 中已有的内容。第三,有人刚刚向我提到了 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}列表来工作。我们必须对分组有点狡猾(可能有更狡猾的方法)。其余的只是从treesTikZ 中的库中修改而来。我在例程中添加了一个钩子,growth这样就可以轻松地将每个级别的样式定义为“对以前样式的一些修改”,而不必专门为每个级别定义样式。使用不同的增长函数可能会产生更像 ESultanik 的答案中给出的示例的东西 - 这个答案的要点是使用循环构建树。

答案3

grahviz您可以使用和的组合dot2tex来生成漂亮的图表。这种组合可以生成漂亮的图表。

答案4

PGF/TikZ 的 CVS 存储库中正在开发一个用于自动(或我们在手册中称之为算法)图形绘制的新库。目前正在研究第一个严肃的图形绘制算法(包括基于力的算法、用于分层绘图(如流程图)的算法以及用于绘制树的算法)。

我不知道树算法的状态,但我们希望此功能(以及我提到的算法)能够在 2011 年某个时候随着新 PGF/TikZ 版本的发布而可用。

相关内容