我想让所有节点从左到右按升序排列。如果我使用fit=band
2 个子树,左右顺序良好,没有任何重叠。但左子树太靠右了,节点 9、11、12 从节点 13 开始就在右边。我不想为这棵树找一个特殊的解决方案,而想为树找一个共同的解决方案。
\documentclass{standalone}
\usepackage{forest}
\makeatletter\tikzset{use path/.code={\tikz@addmode{\pgfsyssoftpath@setcurrentpath#1} \appto\tikz@preactions{\let\tikz@actions@path#1}}}\makeatother
\forestset{show boundary/.style={
before drawing tree={get min s tree boundary=\minboundary, get max s tree boundary=\maxboundary}, tikz+={\draw[red,use path=\minboundary]; \draw[red,use path=\maxboundary];}}}
\begin{document}
\begin{forest}
for tree={l sep=1em, s sep=0.6em, anchor=center,
inner sep=0.3em, fill=red!50,fit=band,
circle,minimum size=20pt, font=\sffamily
},
[13
[4,show boundary
[2]
[5
[,phantom]
[7
[,phantom]
[9
[,phantom]
[11
[,phantom]
[12]
]
]
]
]
]
[19]
]
\end{forest}
\end{document}
[
答案1
13 的幻像子元素位于 4 到 19 之间,并且fit=band
与父元素 13 ( calign with current
) 垂直对齐,这样就可以达到目的。
\documentclass{standalone}
\usepackage{forest}
\makeatletter\tikzset{use path/.code={\tikz@addmode{\pgfsyssoftpath@setcurrentpath#1} \appto\tikz@preactions{\let\tikz@actions@path#1}}}\makeatother
\forestset{show boundary/.style={
before drawing tree={get min s tree boundary=\minboundary, get max s tree boundary=\maxboundary}, tikz+={\draw[red,use path=\minboundary]; \draw[red,use path=\maxboundary];}}}
\begin{document}
\begin{forest}
for tree={l sep=1em, s sep=0.6em, anchor=center,
inner sep=0.3em, fill=red!50,fit=band,
circle,minimum size=20pt, font=\sffamily
},
[13
[4,show boundary
[2]
[5
[,phantom]
[7
[,phantom]
[9
[,phantom]
[11
[,phantom]
[12]
]
]
]
]
]
[,phantom,calign with current]
[19]
]
\end{forest}
\end{document}
编辑:为了更容易输入。可以自动幻化空节点,如下所示。请注意,(i)where content={}{phantom}{}
发生在 内delay
,因为在处理树前导时内容选项未“填充”;并且 (ii)where content
发生在外部 for tree
以避免双重循环。
\documentclass{standalone}
\usepackage{forest}
\makeatletter\tikzset{use path/.code={\tikz@addmode{\pgfsyssoftpath@setcurrentpath#1} \appto\tikz@preactions{\let\tikz@actions@path#1}}}\makeatother
\forestset{show boundary/.style={
before drawing tree={get min s tree boundary=\minboundary, get max s tree boundary=\maxboundary}, tikz+={\draw[red,use path=\minboundary]; \draw[red,use path=\maxboundary];}}}
\begin{document}
\begin{forest}
for tree={l sep=1em, s sep=0.6em, anchor=center,
inner sep=0.3em, fill=red!50,fit=band,
circle,minimum size=20pt, font=\sffamily
},
delay={where content={}{phantom}{}},
[13
[4,show boundary
[2]
[5
[]
[7
[]
[9
[]
[11
[]
[12]
]
]
]
]
]
[,calign with current]
[19]
]
\end{forest}
\end{document}
编辑2:一个通用的自动解决方案。 这个想法是自动fit=band,calign with current
在每对兄弟节点之间插入一个节点。这些节点将充当两个兄弟子树之间的“分隔符”。其他节点则不是需要fit=band
。(与以前的解决方案相比,这可以正确处理一元分支内的二元分支;请参见下面的节点“X”。从代码中删除“X”即可到达原始树。)
事实上,这就是我们解决线性化问题所需要做的一切,所有其他选项都是为了更漂亮的输入;特别coordinate,phantom
是使所有空节点变小且不可见。我还将代码放在样式中,以便于在多棵树中使用。
\documentclass{standalone}
\usepackage{forest}
\forestset{
bst/.style={
delay={
where content={}{
coordinate,phantom
}{
s sep=0.6em, anchor=center,
inner sep=0.3em, fill=red!50,
circle, minimum size=20pt, font=\sffamily,
},
where n children=2{
for 1={insert after={[,coordinate,phantom,calign with current,fit=band]}}
}{},
}
}
}
\begin{document}
\begin{forest} bst
[13
[4
[2]
[5
[]
[7
[X]
[9
[]
[11
[]
[12]
]
]
]
]
]
[19]
]
\end{forest}
\end{document}
编辑 3:使其适用于非二叉分支树。严格来说,这比 OP 想要的要多,但对某些人来说可能有用。这个想法很简单,就是在每对相邻的兄弟节点之间放置分隔节点。这是通过 实现的where n children=0{}{for 1={for following siblings={insert before={...}}}
。
\documentclass{standalone}
\usepackage{forest}
\forestset{
bst/.style={
delay={
where content={}{
coordinate,phantom
}{
s sep=0.6em, anchor=center,
inner sep=0.3em, fill=red!50,
circle, minimum size=20pt, font=\sffamily,
},
where n children=0{}{for 1={for following siblings={
insert before={[,coordinate,phantom,calign with current,fit=band]},
}}},
}
}
}
\begin{document}
\begin{forest} bst
[13
[4
[2]
[5
[]
[7
[X]
[Y
[1]
[2]
]
[9
[]
[11
[]
[12]
]
]
[Z
[4]
[5
[8]
[9]
]
[6]
]
]
]
]
[19]
]
\end{forest}
\end{document}