使用宏定义树子结构的问题

使用宏定义树子结构的问题

相对简单的问题:我想使用宏来定义树的子结构。在下面的例子中,我想定义一些子节点(左和右),以便在树中使用多次。

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%

  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}
\end{document}

问题是

  • 如果没有标签(root)它甚至无法编译(为什么?)

  • 宏不在同一级别展开:右子项成为左子项的子项

  • 使用更多宏或嵌套它们会使情况变得更糟。

这是我想要做的事情的一个非常简化的版本。我经常希望能够手动添加其他子项(不使用宏)。我还希望能够将整个子树定义为宏,例如将长链定义为宏。

我认为宏的扩展存在问题,但我自己无法解决。请帮忙。

干杯,奥利弗

答案1

这类似于

tikz-qtree 中空节点的宏

您需要预先扩展宏,以便 tikz 解析器可以看到它们:

在此处输入图片描述

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}

  \node[circle,draw] (root) {}  child{node[circle,draw] {l}} child{node[circle,draw] {l}} child{node[circle,draw] {r}} child{node[circle,draw] {r}};

 \end{tikzpicture}



aaaaaaaaaaaaaaaaa




  \begin{tikzpicture}

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%

  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}


bbbbbbbbbbbbbbbbbbbbbbbbbbbb

\makeatletter

\let\mypgfutil@ifnch\pgfutil@ifnch
\def\pgfutil@ifnch{%
\let\x@next\@empty
\ifx\pgfutil@let@token\leftchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\ifx\pgfutil@let@token\rightchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\x@next\mypgfutil@ifnch}

\makeatother

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%


  \begin{tikzpicture}


  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}

\end{document}

答案2

c大卫·卡莱尔大师的方法要求始终保持性格。以下是我有时使用的方法。

\documentclass{article}
\usepackage{tikz}
\makeatletter
\newcommand*\tikzcommands{%
  % Collect your tikz commands here, otherwise they will be expanded
  % prematurely:
  \do\begin\do\end\do\coordinate\do\path\do\draw\do\node
}
\def\xtikzpicture{\@ifnextchar'{\@firstoftwo{\xtikz@picture{00}}}%
  {\xtikz@picture{01}}}
\def\xtikz@picture#1#2\end#3{%
  \def\reserved@a{#3}\def\reserved@b{xtikzpicture}%
  \ifx\reserved@a\reserved@b
    \def\endxtikzpicture{}%
    \end{xtikzpicture}%
  \else
    \@latexerr{Environment 'xtikzpicture' badly ended}\@ehd
  \fi
  \let\this@relax\relax
  \def\reserved@a##1\this@relax{}%
  \if#1\expandafter\reserved@a\fi
  \begingroup
  \def\do##1{\let##1\relax}\tikzcommands
  \protected@edef\x{\endgroup
    \begin{tikzpicture}#2\end{tikzpicture}%
  }\x
  \this@relax
}
\makeatother

\def\leftchildren{%
  child{node[circle,draw] {left}}
  child{node[circle,draw] {left}}
}
\def\rightchildren{%
  child{node[circle,draw] {\textcolor{blue}{right}}}
  child{node[circle,draw] {\textcolor{blue}{right}}}
}

\begin{document}
\begin{xtikzpicture}' % ignored
xx
\end{xtikzpicture}

\begin{xtikzpicture}[level distance=10mm,
  every node/.style={fill=red!40,circle,inner sep=1pt}]
  % Maybe someone can tell me why the circle on 'root' has no effect:
  \node {root} [grow'=up,circle,draw] 
  \leftchildren \rightchildren
  child {node {parent}
    child {node {child}}
    child {node {child}}
  };
\end{xtikzpicture}
\end{document}

在此处输入图片描述

答案3

使用forest,您可以轻松指定复杂的子树,以不同的方式格式化它们,并在树中混合显式和自动节点创建。而且您可以非常简洁地完成所有这些操作,而无需担心扩展问题。(至少,通常不需要。)

例如:

\documentclass[tikz,border=5pt,multi]{standalone}

\usepackage{forest}

\begin{document}

\forestset{
  my circle/.style={circle, draw},
  my node/.style={draw},
  left children/.style={
    repeat=2{prepend={[l, my circle]}}
  },
  right children/.style={
    repeat=2{append={[r, my circle]}}
  },
  complex children/.style={
    before typesetting nodes={for descendants={my node}},
    append={[+1, left children, delay={for children={right children}}, before typesetting nodes={for tree={blue, edge={blue}}}, insert after={[+2, repeat=3{prepend={[p, for tree={green, edge={green}}[p]]}, append={[a, for tree={red, edge={red}}]}}]}]}
  }
}
\begin{forest}
  [, my circle, left children, right children
    [, my circle, complex children]
  ]
\end{forest}

\end{document}

该样式my circle只是将节点形状设置为圆形并绘制它。

样式left childrenright children相对于当前节点使用该my circle样式创建 2 个左子节点和 2 个右子节点。

该样式complex children会创建一个由左侧 ( +1) 和右侧 ( +2) 组成的子树。默认情况下,此子树中的所有节点都使用 样式,my node该样式在默认的矩形节点形状周围绘制一个框。左侧为蓝色,根节点使用该my node样式,但其子节点使用该my circle样式,因为它们是使用left children和创建right children的。右侧最初没有颜色,但此侧的子节点有颜色。左侧的 3 个子节点为绿色,它们的子节点也是绿色。右侧的 3 个子节点为红色。依此类推。

显然,您可以根据需要定义更简单或更复杂的结构和样式。

使用 <code>forest</code> 样式的自动化节点结构

答案4

您还可以使用以下命令强制扩展宏\edef

\edef\tmp{\leftchildren \rightchildren}
\node[circle,draw] (root) {} \tmp;

相关内容