前段时间我发现了一个问题使用 tikz 绘制图形的邻接表表示并想解决这个问题。我可以,但仍然存在一些问题,我应该如何绘制单/双链表?提醒我他们。
我的解决方案是:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix,arrows}
\begin{document}
\begin{tikzpicture}[>=stealth]
\matrix (M) [matrix of nodes,%
column sep=0pt,%
row sep=1mm,%
nodes={draw, fill=gray!20,%
minimum width=.5cm, outer sep=0pt,%
minimum height=.7cm, anchor=center},
column 1/.style={minimum height=.8cm}]%
{
\mbox{} &[2mm] 2 & \mbox{} &[2mm] 5 & / &[2mm] & &[2mm] & \\
\mbox{} & 1 & \mbox{} & 5 & \mbox{} & 3 & \mbox{} & 4 & / \\
\mbox{} & 2 & \mbox{} & 5 & \mbox{} & 3 & / & & \\
};
\foreach \i in {1,2,3}{
\path (M-\i-1) [late options={label=left:\i}];
\draw[->] (M-\i-1)--(M-\i-2.west);
\draw[->] (M-\i-3.center)--(M-\i-4.west);
}
\draw[->] (M-2-5.center)--(M-2-6.west);
\draw[->] (M-2-7.center)--(M-2-8.west);
\draw[->] (M-3-5.center)--(M-3-6.west);
\begin{scope}[yshift=-3cm]
\matrix (M) [matrix of nodes,%
column sep=0pt,%
row sep=1mm,%
nodes={draw, fill=gray!20,%
minimum width=.5cm, outer sep=0pt,%
minimum height=.7cm, anchor=center},
column 1/.style={minimum height=.8cm}]%
{
|[label=left:1]| \mbox{} &[2mm] 2 &\mbox{}&[2mm] 5 & / &[2mm] & &[2mm] & \\
|[label=left:2]|\mbox{} & 1 & \mbox{} & 5 & \mbox{} & 3 & \mbox{} & 4 & / \\
|[label=left:3]| \mbox{} & 2 & \mbox{} & 5 & \mbox{} & 3 & / & & \\
};
\foreach \i in {1,2,3}{
% \path (M-\i-1) [late options={label=left:\i}];
\draw[->] (M-\i-1)--(M-\i-2.west);
\draw[->] (M-\i-3.center)--(M-\i-4.west);
}
\draw[*->] (M-2-5.center)--(M-2-6.west);
\draw[*->] (M-2-7.center)--(M-2-8.west);
\draw[*->] (M-3-5.center)--(M-3-6.west);
\end{scope}
\end{tikzpicture}
\end{document}
有此结果
现在有一些问题:
1- 我使用 \mbox{} 来区分“空节点”和“空单元格”。您知道更好的解决方案吗?
2- 尽管column 1/.style
声明了第一列的框,但它们的高度与其他框的高度相同。为什么?
3- 使用labels
节点内(底部示例)更改node
(或cell
?)中心。可以使用(上部示例)避免此问题late options
。您知道更好的选择吗?
4- 从上例中看第一列和第二列,似乎节点的名称不等同于 node.center。你知道为什么吗?
5- 我不知道这是否是渲染问题,但看起来相邻单元格的分隔线较粗。列分隔线必须是多少才能将一个单元格的边框线绘制在另一个单元格上?
6- 解决方案我应该如何绘制单/双链表?显示起点*->
,但这里它的行为就像修改*
并o
设置 tikz 箭头的样式,使其位于行尾的中心。你能解释一下为什么吗?
答案1
- 在创建空节点时,您可以使用
{}
而不是\mbox{}
来节省一些输入。正如 ipavlic 在他的评论中指出的那样,您也可以使用键nodes in empty cells
。这意味着您无法指定第一行中列之间的所有额外间隙,因为这会创建大量不正确的空节点。相反,您必须在首次使用它们的行中指定额外的间隙。 - 您需要使用
column 1/.style={nodes={minimum height=0.8cm}}
来更改节点行为。如果不使用nodes=...
,则基本上会更改适用于整个矩阵的选项,而不是节点(请参阅节点矩阵列样式不一致了解更多信息)。 - 它不会改变中心,而是为标签分配节点名称 (
M-1-1
)。您可以通过将选项添加every label/.append style={name={}}
到矩阵来防止这种情况。(请参阅答案末尾的示例以进行演示) 这是指定没有锚点的节点名称的正常行为。引自pgfmanual,第 16.11 节:“当您说 时
(x)--(1,1)
,--
路径操作不会从 的中心画一条线x
,而是从 的边界x
沿着朝向 的方向画一条线(1,1)
”为了使线条重叠,列之间的距离必须为
-\pgflinewidth
。参见TikZ 矩阵作为表格的替代品。在我应该如何绘制单/双链表?,
*-
线条从多部分节点的水平位置开始<node>.two
,这不是第二个节点部分的中心,但实际上略微向左移动(替换*->
为--
以查看线条实际开始的位置)。对于*-
箭头样式,这很方便。由于您不使用多部分节点,而是每个矩形使用一个节点,因此您没有该锚点,并且必须求助于使用shorten < = -2pt
。
这是您的代码以及建议的更改:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix,arrows,fit}
\tikzset{circarrow/.style={
*->,
shorten <=-2pt
}
}
\begin{document}
\begin{tikzpicture}[>=stealth]
\matrix (M) [matrix of nodes,%
column sep=-\pgflinewidth,%
row sep=1mm,%
nodes in empty cells,
nodes={draw, fill=gray!20,%
minimum width=.5cm, outer sep=0pt,%
minimum height=.7cm, anchor=center},
column 1/.style={nodes={minimum height=.8cm}}]%
{
&[2mm] 2 & &[2mm] 5 & / \\
& 1 & & 5 & &[2mm] 3 & &[2mm] 4 & / \\
& 2 & & 5 & & 3 & /\\
};
\foreach \i in {1,2,3}{
\path (M-\i-1) [late options={label=left:\i}];
\draw[->] (M-\i-1)--(M-\i-2.west);
\draw[->] (M-\i-3.center)--(M-\i-4.west);
}
\draw[->] (M-2-5.center)--(M-2-6.west);
\draw[->] (M-2-7.center)--(M-2-8.west);
\draw[->] (M-3-5.center)--(M-3-6.west);
\begin{scope}[yshift=-3cm]
\matrix (M) [matrix of nodes,%
column sep=-\pgflinewidth,%
row sep=1mm,%
nodes in empty cells,
nodes={draw, fill=gray!20,%
minimum width=.5cm, outer sep=0pt,%
minimum height=.7cm, anchor=center},
column 1/.style={nodes={minimum height=.8cm}},
every label/.append style={name={}}]%
{
|[label=left:1]| &[2mm] 2 & &[2mm] 5 & / \\
|[label=left:2]|& 1 & & 5 & &[2mm] 3 & &[2mm] 4 & / \\
|[label=left:3]| & 2 & & 5 & & 3 & / & & \\
};
\foreach \i in {1,2,3}{
%\path (M-\i-1) [late options={label=left:\i}];
\draw[->] (M-\i-1)--(M-\i-2.west);
\draw[->] (M-\i-3.center)--(M-\i-4.west);
}
\draw[circarrow] (M-2-5.center)--(M-2-6.west);
\draw[circarrow] (M-2-7.center)--(M-2-8.west);
\draw[circarrow] (M-3-5.center)--(M-3-6.west);
\end{scope}
\end{tikzpicture}
\end{document}
label
如何改变矩阵中节点的名称(而不是扩展节点)的示例:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix,fit}
\begin{document}
\begin{tikzpicture}
\matrix (M) [matrix of nodes,%
row sep=1mm,%
nodes={draw, fill=gray!20,%
minimum width=.5cm, outer sep=0pt,%
minimum height=.7cm, anchor=center}
]%
{
|[label=left:1]| &[2mm] 2\\
|[label={[name=none]left:2}]|& 1\\
};
\foreach \i in {1,2}{
\draw[->] (M-\i-1)--(M-\i-2.west);
\node [fit=(M-\i-1),draw,red] {};
}
\end{tikzpicture}