重新创建一棵树,增加在两个现有节点中间添加节点的难度

重新创建一棵树,增加在两个现有节点中间添加节点的难度

这是, 哪个成本加运费亲切地提供了答案,并根据 cfr 针对我的评论提出的建议,我以新问题的形式提出它。目标是重新创建下面的图像

在此处输入图片描述

现在,我搜索了森林手册关于如何在两个已经存在的节点中间添加一个节点,但找不到方法。我尝试使用 TikZ 手册第 30 章的说明,即图形绘制布局:树,但遗憾的是我不能使用lualatex,因为我需要利用xepersian。我尝试使用trees库,但输出却大不相同且丑陋。如果这个问题没有体现出努力或研究,我很抱歉。这真的超出了我的理解范围。我提前感谢您的帮助。

答案1

我用了cfr 的精彩回答您似乎在问题中提到了这一点,并将其进一步扩展,以便可以在两个级别之间添加另一个节点:

\documentclass[border=10pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{forest}
  for tree={
    circle,
    fill=black,
    edge={{Latex[length=6pt,width=3pt]}-},
    grow'=north,
    calign=fixed edge angles,
    inner sep=0.5pt,
  },
  before typesetting nodes={
    for tree={
      my label/.option=content,
      content={.},
    }
  },
  additional/.style={
    edge path/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {
        \noexpand\path
            (!u.parent anchor) -- (.child anchor) 
            node[midway, circle, fill=black, inner sep=0.5pt, label={##1:$#1$}] (m) {.};
        \noexpand\path[\forestoption{edge}]
            (!u.parent anchor) -- (m); 
        \noexpand\path[\forestoption{edge}]
            (m) -- (.child anchor) 
            \forestoption{edge label};
        }
    }
  },
  my label/.style={
    label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
  },
  [g 
    [e 
      [c,additional={c'}
        [a ]
        [b ]
      ]
      [d ]
    ]
    [f,additional={f'} ]
  ]
\end{forest}
\end{document}

在此处输入图片描述


手动添加级别数字可能最容易。您只需在环境的最后放置\nodes即可。forest坐标默认等于级别,因此放置节点相当容易:

\documentclass[border=10pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{forest}
  for tree={
    circle,
    fill=black,
    edge={{Latex[length=6pt,width=3pt]}-},
    grow'=north,
    calign=fixed edge angles,
    inner sep=0.5pt,
  },
  before typesetting nodes={
    for tree={
      my label/.option=content,
      content={.},
    }
  },
  additional/.style={
    edge path/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {
        \noexpand\path
            (!u.parent anchor) -- (.child anchor) 
            node[midway, circle, fill=black, inner sep=0.5pt, label={##1:$#1$}] (m) {.};
        \noexpand\path[\forestoption{edge}]
            (!u.parent anchor) -- (m); 
        \noexpand\path[\forestoption{edge}]
            (m) -- (.child anchor) 
            \forestoption{edge label};
        }
    }
  },
  my label/.style={
    label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
  },
  [g 
    [e 
      [c,additional={c'}
        [a ]
        [b ]
      ]
      [d ]
    ]
    [f,additional={f'} ]
  ]
  \foreach \l in {1,...,4} {
    \node at (2,{\l-1}) {$\l$};
  } 
  \node at (2,0.5) {$1\frac{1}{2}$};
  \node at (2,1.5) {$2\frac{1}{2}$};
  \node at (2,3.5) {Level};  
\end{forest}
\end{document}

在此处输入图片描述

自动化解决方案会更加棘手,尤其是考虑到中间节点。

答案2

这个答案既尝试回答这个新问题,也纠正了我的答案前一个. 虽然在原始示例,试图延伸我之前的回答画出树这个问题说明了一个问题。

暂时忽略中间节点和层标签,扩展树的基本结构的明显方法是

  [g 
    [e 
      [c, 
        [a ]
        [b_2 [, phantom][b_1]]
      ]
      [d_3, [, phantom][d_2 [, phantom][d_1]]]
    ]
    [f_5 [, phantom][f_4,  [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
  ]

结合我之前的回答的序言,我们发现了这个问题:

问题例证

我们希望以下节点集水平对齐:

  • b1--d1--f2
  • a--b2--d2--f3
  • c--b3--d3--f4
  • d--f5

但是,只有最后一对是水平对齐的。在前三组节点中,f 节点低于其同层节点。

这是因为forest尝试同时对齐层上的节点并确保fixed edge angles直线。它执行其中一项,但在执行另一项时,它会部分撤消第一项。删除任何一个选项都会使我们离期望的结果越来越远。

基本上,将节点与层对齐和使用之间存在冲突fixed edge angles。可以解决这个问题,但我不知道有什么现成的解决方案,所以它有点复杂。

这可能无法处理所有极端情况,但它应该能够更好地处理更多数量的边(和节点!)树。

\begin{forest}
  aligned tree,
  label tiers,
  [g 
    [e 
      [c, double here
        [a ]
        [b_2 [, phantom][b_1]]
      ]
      [d_3, double here [, phantom][d_2 [, phantom][d_1]]]
    ]
    [f_5 [, phantom][f_4, double here [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
  ]
\end{forest}

额外的半级别以及冲突的固定边缘角度和层对齐的修正

aligned tree是我之前回答中发布的代码的修改版本,为了方便起见,将其变成了一种样式。当前版本declare的自定义forest选项并不总是在环境中起作用forest,因此我发现事先设置好一切会更容易。

label tiers标记级别,如果适用,则标记半级别。格式由样式定义决定,显然可以根据需要进行调整。

double here导致插入一个附加节点。此节点不是树结构的一部分。它只是作为从父节点绘制边的一部分而构建的。因此,它与Jasper Habicht 的回答

完整代码:

\documentclass[11pt]{book}
% atebion: https://tex.stackexchange.com/a/703530/ a https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{amsmath}
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\forestset{%
  declare toks={double content}{},
  declare boolean={doubled level}{0},
  my label/.style={%
    label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
  },
  my double label/.style 2 args={%
    edge path'={%
      (!u.parent anchor) edge node (a) [pos=1,inner sep=.5pt,circle,fill,label=#2:{$#1$}] {.} ($(!u.parent anchor)!.5!(.child anchor)$) (a) -- (.child anchor) 
    },
  },
  aligned tree/.style={%
    for tree={
      circle,
      fill=black,
      edge={{Latex[length=6pt,width=3pt]}-},
      grow'=north,
      calign=fixed angles,
      inner sep=0.5pt,
    },
    before typesetting nodes={
      for tree={%
        my label/.option=content,
        content={.},
        tier/.process={Ow+n{level}{##1+1}},
      },
    },
    align to tier,
  },
  double here/.style={%
    content+={'},
    double content/.option=content,
    double content+={'},
    before typesetting nodes={%
      my double label/.process={ O  Od< ?  {double content}  {x}{0pt} {left}{right} },
      tempcountb/.option=level,
      sort by={>O+n{id}},
      for nodewalk={%
        filter={root',descendants}{>O+nR={level}{tempcountb}},
      }{doubled level},
    },
  },
  align to tier/.style={%
    before computing xy={%
      tempdima/.max={l}{tree},
      tempdimb/.max={s}{tree},
      for descendants={%
        l/.register=tempdima,
        if={>Od>{s}{0pt}}{s/.register=tempdimb}{s=-\foresteregister{tempdimb}},
      },
    },
  },
  label tiers/.style={%
    before drawing tree={%
      tempcounta/.max={level}{tree},
      tikz+={\node  [level label,anchor=south west] (x) at ([xshift=15pt,yshift=5pt]current bounding box.north east) {Levels};},
      for nodewalk={%
        do until={>OR={level}{tempcounta}}{fake=next leaf},
        do until={>O!{phantom}}{fake=next on tier},
        current and ancestors
      }{%
        tikz+/.process={Ow{tier}{\node (tier label ##1) [level label] at (.center -| x.center) {$##1$};}},
        if={>O{doubled level}}{%
          tikz+/.process={Ow{level}{%
              \path (!u.center -| x.center) -- (.center -| x.center) node [level label,midway] {$##1\frac{1}{2}$} ;
            }%
          }
        }{},
      },
    },
  },
  /tikz/level label/.style={anchor=center,font=\sffamily},
}
\begin{document}
\begin{forest}
  aligned tree,
  label tiers,
  [g 
    [e 
      [c, double here
        [a ]
        [b_2 [, phantom][b_1]]
      ]
      [d_3, double here [, phantom][d_2 [, phantom][d_1]]]
    ]
    [f_5 [, phantom][f_4, double here [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
  ]
\end{forest}
\end{document}

相关内容