森林:搜索节点匹配标准

森林:搜索节点匹配标准

我正在使用森林来绘制数据结构(特别是 AVL- / (a,b)-树)。我想自动绘制所有叶子之间的连接线(到目前为止,我已经手动命名它们并使用 foreach 语句绘制线条,这有点烦人)。

以下方法有些有效:

for tree={edge={->},if n children=0{}{treenode}},
for leaves={leafnode,tier=list,if={id()!=id("!rL")}{tikz={\draw[<->,thick,gray] () -- (!>);}}{}},
for root={rootnode}
[5 & 19,align=cc
  [5] [19] [$\infty$]
]

(这id()!=id("!rL")是我能想到的唯一方法来检测当前叶子是否不是最后一片,因为没有!>定义)

但是,我还想在不改变布局的情况下对节点的插入/删除进行动画处理,即添加幻影节点

for tree={edge={->},if n children=0{}{treenode}},
for leaves={leafnode,tier=list,if={id()!=id("!rL")}{tikz={\draw[<->,thick,gray] () -- (!>);}}{}},
for root={rootnode}
[5,align=c
  [5] [,phantom] [$\infty$]
]

现在,幻影节点仍然被视为下一个(后来不存在的)兄弟节点,但我想直接从节点 5 到 $\infty$ 节点画一条线。

我能以某种方式搜索下一个非幻像(或非空内容)兄弟吗?我无法理解森林的while/until构造,而且例子似乎很少。

编辑:抽象地说,我认为问题可以归结为“如何获取满足 nodewalk 中条件的第一个节点的句柄”

编辑2:MWE

\documentclass{article}
\usepackage{tikz,forest}

\begin{document}
    \tikzset{box/.style={draw,rectangle,minimum height=0.7cm,minimum width=1cm}}
    \begin{forest}
        for tree={edge={->},anchor=north,box},
        for leaves={tier=list,if={id()!=id("!rL")}{tikz={\draw[<->] () -- (!>);}}{}},
        [x
            [a]
            [b]
            [c]
        ]
    \end{forest}
\end{document}

答案1

这里有两种方法可以做到这一点。 两者都采用了相同的基本思想:我们访问非幻影叶,使用alias'=last记住先前访问的节点,并使用处理程序将id前一个节点的 放入代码中。(我们只在指向有效节点时绘制,这由 检查,我们在开始时初始化为无效节点。)tikz.processlastif nodewalk validlast

第一种方法用于where访问非幻像叶子节点。第一个参数是一个表达式。和pgfmath的组合也可以。(请注意,从技术上讲,这不是节点行走。)where n childrenif phantomwhere

\documentclass{article}
\usepackage{forest}

\begin{document}
\tikzset{box/.style={draw,rectangle,minimum height=0.7cm,minimum width=1cm}}
\begin{forest}
  for tree={edge={->},anchor=north,box},
  % We delay to process the "phantom"s in the tree first:
  delay={
    % Set name "last" to an invalid node. Argh, cumbersome:
    for nodewalk={on invalid={fake}{id=0,alias'=last}}{},
    % Visit the non-phantom leaves:
    where={n_children==0 && !phantom}{
      if nodewalk valid={name=last}{% Do we have the "last" node?
        % Yes. Identifying the current node inside \draw is not a problem:
        % "()".  Possibly the best way to refer to the last node inside TikZ
        % code (which is executed much much later) is to paste its "id" there.
        % In ".process", "O" gets the option (name.option), and "w" injects
        % that into the code as "#1".
        tikz+/.process=Ow {last.id}{
          \draw[red, thick]()--(!id=#1);
        },
      }{% The "false" branch of "if nodewalk valid".
      },
      % Name the current node as last.
      alias'=last,
    }{% The "false" branch of "where".
    },
  },
  [x
    [a]
    [b]
    [,phantom]
    [c]
  ]
\end{forest}
\end{document}

第二种方式使用真实的 nodealk。我们使用表达式进行filternodewalk 。leavespgfmath!phantom

\documentclass{article}
\usepackage{forest}

\begin{document}
\tikzset{box/.style={draw,rectangle,minimum height=0.7cm,minimum width=1cm}}
\begin{forest}
  for tree={edge={->},anchor=north,box},
  delay={
    for nodewalk={on invalid={fake}{id=0,alias'=last}}{},
    % Filtering: walk the leaves of the tree, and step on those that are not phantom.
    for filter={leaves}{!phantom}{
      if nodewalk valid={name=last}{
        tikz+/.process=Ow {last.id}{
          \draw[red, thick]()--(!id=#1);
        },
      }{},
      alias'=last,
    },
  },
  [x
    [a]
    [b]
    [,phantom]
    [c]
  ]
\end{forest}
\end{document}

两种变体的结果

答案2

发布后,我偶然发现了define long step森林文档中的示例。这似乎有效:

\documentclass{article}
\usepackage{tikz,forest}

\begin{document}
    \tikzset{box/.style={draw,rectangle,minimum height=0.7cm,minimum width=1cm}}
    \forestset{
        define long step={nextleaf}{n args=0}{do while={>{O}{phantom}}{next on tier}},
        connect leaves/.style={delay={if={>{O!P&}{phantom}{id()!=id("!rL")}}{tikz={\draw[-] () -- (!nextleaf);}}{}}}
    }
    \begin{forest}
        for tree={anchor=north,box},
        for leaves={tier=list,connect leaves}
        [x
            [a]
            [b]
            [c]
        ]
    \end{forest}
\end{document}

但我仍然想不出更好的方法来检查当前节点是否位于树的末端。

相关内容