编辑

编辑

我正在使用 TikZ 在 latex 中绘制递归树,我的问题是一些圆圈重叠,我似乎无法弄清楚原因。此外,有没有办法在连接父节点和其子节点的线上放置一些文本?

这是我的代码。

\documentclass[11pt,a4paper,oneside]{article}
\usepackage{fullpage}
\usepackage[italian]{babel}
\usepackage[utf8]{inputenc}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{tikz}

\begin{document}
\begin{figure}[hb]
    \centering
    \begin{tikzpicture}[level/.style={sibling distance=30mm/#1}]
        \node[circle,draw](z){$n$}
            child{node [circle,draw] (a) {$\frac{n}{4}$}
                child{node [circle,draw] (d) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (e) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (f) {$\frac{n}{4^2}$}}
            }
            child{node [circle,draw] (b) {$\frac{n}{4}$}
                child{node [circle,draw] (g) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (h) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (k) {$\frac{n}{4^2}$}}
            }
            child{node [circle,draw] (c) {$\frac{n}{4}$}
                child{node [circle,draw] (l) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (m) {$\frac{n}{4^2}$}}
                child{node [circle,draw] (n) {$\frac{n}{4^2}$}}
            };
        \path (a) -- (b) node [midway] {+};
        \path (b) -- (c) node [midway] {+};
        \path (d) -- (e) node [midway] {+};
        \path (e) -- (f) node [midway] {+};
        \path (f) -- (g) node [midway] {+};
        \path (g) -- (h) node [midway] {+};
        \path (h) -- (k) node [midway] {+};
        \path (k) -- (l) node [midway] {+};
        \path (l) -- (m) node [midway] {+};
        \path (m) -- (n) node [midway] {+};

    \end{tikzpicture}
\end{figure}
\end{document}

答案1

您还可以使用forest它来为您计算最小距离。

注意:我确信,作为递归图,以下代码可以简化,但我不知道该怎么做。这只是一个易于理解的解决方案。

\documentclass[11pt, a4paper,oneside]{article}
\usepackage{fullpage}
\usepackage[italian]{babel}
\usepackage[utf8]{inputenc}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{forest}

\begin{document}
\begin{figure}[hb]
    \centering
    \begin{forest}
    [$n$, for tree={circle, draw}
        [$\frac{n}{4}$, name=a
            [$\frac{n}{4^2}$, name=d]
            [$\frac{n}{4^2}$, name=e]
            [$\frac{n}{4^2}$, name=f]]
        [$\frac{n}{4}$, name=b
            [$\frac{n}{4^2}$, name=g]
            [$\frac{n}{4^2}$, name=h]
            [$\frac{n}{4^2}$, name=i]]
        [$\frac{n}{4}$, name=c
            [$\frac{n}{4^2}$, name=j]
            [$\frac{n}{4^2}$, name=k]
            [$\frac{n}{4^2}$, name=l]]]
          \path (a) -- (b) node [midway] {+};
        \path (b) -- (c) node [midway] {+};
        \path (d) -- (e) node [midway] {+};
        \path (e) -- (f) node [midway] {+};
        \path (f) -- (g) node [midway] {+};
        \path (g) -- (h) node [midway] {+};
        \path (h) -- (i) node [midway] {+};
        \path (i) -- (j) node [midway] {+};
        \path (j) -- (k) node [midway] {+};
        \path (k) -- (l) node [midway] {+};
    \end{forest}
\end{figure}
\end{document}

在此处输入图片描述

更新:遵循 cfr 建议,math contents sep已引入。

\documentclass[11pt, a4paper,oneside]{article}
\usepackage{fullpage}
\usepackage[italian]{babel}
\usepackage[utf8]{inputenc}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{forest}

\begin{document}
\begin{figure}[hb]
    \centering
    \begin{forest}
    [n, for tree={circle, draw, math content, s sep=1em}
        [\frac{n}{4}, name=a
            [\frac{n}{4^2}, name=d]
            [\frac{n}{4^2}, name=e]
            [\frac{n}{4^2}, name=f]]
        [\frac{n}{4}, name=b
            [\frac{n}{4^2}, name=g]
            [\frac{n}{4^2}, name=h]
            [\frac{n}{4^2}, name=i]]
        [\frac{n}{4}, name=c
            [\frac{n}{4^2}, name=j]
            [\frac{n}{4^2}, name=k]
            [\frac{n}{4^2}, name=l]]]
          \path (a) -- (b) node [midway] {+};
        \path (b) -- (c) node [midway] {+};
        \path (d) -- (e) node [midway] {+};
        \path (e) -- (f) node [midway] {+};
        \path (f) -- (g) node [midway] {+};
        \path (g) -- (h) node [midway] {+};
        \path (h) -- (i) node [midway] {+};
        \path (i) -- (j) node [midway] {+};
        \path (j) -- (k) node [midway] {+};
        \path (k) -- (l) node [midway] {+};
    \end{forest}
\end{figure}
\end{document}

在此处输入图片描述

答案2

对于重叠节点,重要的观察是sibling distance指定同一父节点的子节点之间的间距,而不是给定级别上所有节点之间的间距。您的示例中的相关行是

\begin{tikzpicture}[level/.style={sibling distance=30mm/#1}]

指定第 n 级的兄弟节点(同一节点的子节点)应彼此间隔 30/n 毫米。因此,第 1 级(第 0 级为根节点)的节点相距 30 毫米。同时,第 2 级的右子节点位于其父节点右侧 15 毫米处,左子节点位于其父节点左侧 15 毫米处它是父母,它和父母的左兄弟的右孩子位于同一位置。

要解决此问题,您需要更改该行。例如,如果您希望拥有一个具有多层的完整三叉树,并且希望第 n 层上的 3^n 个节点均匀分布(对于所有层),您可以使用

\begin{tikzpicture}[level/.style={sibling distance=120mm/3^#1}]

(此处 120mm 似乎对于您拥有的 3 个层来说已经足够了,但您必须增加该缩放因子以避免后续层重叠)。您还可以为每一层明确设置同级距离:

\begin{tikzpicture}[level 1/.style={sibling distance=42mm}, level 2/.style={sibling distance=14mm}]

要向边添加标签,请将其附加edge from parent node {Your Label}在子节点声明之后,例如,

child{node [circle,draw] (a) {$\frac{n}{4}$} edge from parent node {Your Label}

您可以像任何其他节点一样设置边缘标签节点的样式(例如,使用......edge from parent node[left]将标签放置在边缘中点的左侧)。

答案3

Ignasi 建议我也许能够“改进”森林解决方案。

我不得不说,这段代码几乎不能被指责为更简单。然而,它更加自动化。森林本身根据两条信息构建树的各个方面:根以下的级别数和每个非终端节点的分支数。

也可以指定分母中使用的因子,但这不是必需的。如果没有给出,则将使用分支数加 1。

默认情况下使用 2 个级别和 3 个分支,如 Ignasi 的示例一样。

要使用该样式,请添加rstyle到树的序言中。

  • rbranches=<integer>指定每个非终端节点的分支数;
  • rlevels=<integer>指定根以下的级别数。

如果需要覆盖分母中使用的因子,请使用

  • rdenom=<integer>

因此,我们可以绘制如下的3棵树。

首先,我们测试默认设置以匹配 Ignasi 的示例。我增加了一些间距,因为我最初不知道底层有附加符号。

\begin{forest}
  rtree,
  []
\end{forest}

3x2

现在让我们尝试一棵具有默认分支数但附加一个级别的树,但我们将在这里明确说明所有内容。

\begin{forest}
  rtree,
  rbranches'=3,
  rlevels'=3,
  []
\end{forest}

3x3

最后,让我们将分支减少到 2 个,但将级别增加到 5 个。

\begin{forest}
  rtree,
  rbranches'=2,
  rlevels'=5,
  []
\end{forest}

2x5

完整代码:

% addaswyd o côd Ignasi: http://tex.stackexchange.com/a/333886/
\documentclass[border=10pt,tikz]{standalone}
\usepackage{forest}
\forestset{
  declare count register=rlevels,
  declare count register=rbranches,
  declare count register=rdenom,
  declare count register=rwait,
  rlevels'=2,
  rbranches'=3,
  rdenom'=0,
  rwait'=1,
  define long step={rup}{}{fake=root,first leaf,ancestors},
  rtree/.style={
    delay={
      repeat/.wrap pgfmath arg={
        {##1}{
          rwait'+=2,
          delay n/.wrap pgfmath arg={
            {########1}{
              where n children=0{
                repeat/.wrap pgfmath arg={
                  {################1}{
                    append={[]}
                  }
                }{rbranches},
              }{},
            }
          }{rwait},
        }
      }{rlevels},
    },
    before typesetting nodes={
      if={(rdenom)==0}{
        rdenom/.register=rbranches,
        rdenom'+=1,
      }{},
      for tree={
        circle,
        draw,
        math content,
        s sep+=5pt,
      },
      where level=0{
        content=n,
      }{
        if level=1{
          content=\frac{n}{\foresteregister{rdenom}},
        }{
          content/.wrap pgfmath arg={\frac{n}{\foresteregister{rdenom}^{##1}}}{level()},
        },
      },
    },
    before drawing tree={
      for rup={
        tempkeylista'=,
        for nodewalk/.wrap pgfmath arg={
          {fake=root,filter={descendants}{(level())==##1}}{tempkeylista/.option=name}
        }{level()},
        radd/.register=tempkeylista,
      },
    }
  },
  radd/.style={
    tikz+={
      \foreach \i [remember=\i, count=\k, remember=\i as \j] in {#1}
      \ifnum\k=1\relax\else\path  (\i) -- (\j) node [midway] {$+$}\fi;
    },
  },
}
\begin{document}
\begin{forest}
  rtree,
  []
\end{forest}
\begin{forest}
  rtree,
  rbranches'=3,
  rlevels'=3,
  []
\end{forest}
\begin{forest}
  rtree,
  rbranches'=2,
  rlevels'=5,
  []
\end{forest}
\end{document}

编辑

这说明了如何根据 Forest 填写的模板自动向父节点和子节点之间的边添加标签。出于演示目的,我使用了模板

Step <level of recursion>: Branch <number of branch>

对于大多数标签,文本在分支上方呈一定角度。如果分支数量为奇数,则中间子标签将分成两行并水平放置,后面填充白色,以避免分支穿过标签而显得不美观。

当使用标签时(如在默认情况下),树会稍微间隔开以给标签留出空间。当然,如果模板大小明显不同,则需要进行调整。

可以使用 关闭标签not rtree labels,或者用 明确打开标签rtree labels

使用扩展样式,与上述三棵树相同的代码会自动生成标记的版本。

第一棵树自动标记

第二棵树自动标记

第三棵树自动标记

% ateb: http://tex.stackexchange.com/a/333904/ addaswyd o côd Ignasi: http://tex.stackexchange.com/a/333886/
\documentclass[border=10pt,tikz]{standalone}
\usepackage{forest}
\forestset{
  declare count register=rlevels,
  declare count register=rbranches,
  declare count register=rdenom,
  declare count register=rwait,
  declare boolean register=rtree labels,
  rtree labels,
  rlevels'=2,
  rbranches'=3,
  rdenom'=0,
  rwait'=1,
  define long step={rup}{}{fake=root,first leaf,ancestors},
  rtree/.style={
    delay={
      repeat/.wrap pgfmath arg={
        {##1}{
          rwait'+=2,
          delay n/.wrap pgfmath arg={
            {########1}{
              where n children=0{
                repeat/.wrap pgfmath arg={
                  {################1}{
                    append={[, redge label/.wrap 2 pgfmath args={Step ################################################################1: Branch ################################################################2}{level()}{n()}]}
                  }
                }{rbranches},
              }{},
            }
          }{rwait},
        }
      }{rlevels},
    },
    before typesetting nodes={
      if={(rdenom)==0}{
        rdenom/.register=rbranches,
        rdenom'+=1,
      }{},
      for tree={
        circle,
        draw,
        math content,
        s sep+=5pt,
        if rtree labels={
          l sep+=15pt,
        }{},
      },
      where level=0{
        content=n,
      }{
        if level=1{
          content=\frac{n}{\foresteregister{rdenom}},
        }{
          content/.wrap pgfmath arg={\frac{n}{\foresteregister{rdenom}^{##1}}}{level()},
        },
      },
    },
    before packing={
      if rtree labels={
        where n children=0{
          !u.l sep+=30pt,
          !u.s sep+=20pt,
          if level=1{}{
            !uu.l sep+=20pt,
            if level=2{}{
              !uuu.l sep+=10pt,
            },
          },
        }{},
      }{},
    },
    before drawing tree={
      for rup={
        tempkeylista'=,
        for nodewalk/.wrap pgfmath arg={
          {fake=root,filter={descendants}{(level())==##1}}{tempkeylista/.option=name}
        }{level()},
        radd/.register=tempkeylista,
      },
    }
  },
  radd/.style={
    tikz+={
      \foreach \i [remember=\i, count=\k, remember=\i as \j] in {#1}
      \ifnum\k=1\relax\else\path  (\i) -- (\j) node [midway] {$+$}\fi;
    },
  },
  redge label/.style={
    if rtree labels={
      if={(n())<(((rbranches)+1)/2)}{
        edge label={node [midway, font=\scriptsize, above, sloped] {#1}},
      }{
        if={(n())>(((rbranches)+1)/2)}{
          edge label={node [midway, font=\scriptsize, above, sloped] {#1}},
        }{
          temptoksa={#1},
          split register={temptoksa}{:}{temptoksb,temptoksc},
          edge label/.wrap 2 pgfmath args={node [midway, font=\scriptsize, align=center, fill=white] {##1:\\##2}}{temptoksb}{temptoksc},
        },
      },
    }{},
  },
}
\begin{document}
\begin{forest}
  rtree,
  []
\end{forest}
\begin{forest}
  rtree,
  rbranches'=3,
  rlevels'=3,
  []
\end{forest}
\begin{forest}
  rtree,
  rbranches'=2,
  rlevels'=5,
  []
\end{forest}
\end{document}

相关内容