# auto adjust node position in a binary tree

I'm trying to draw a binary tree using tikz. I use shift option to define the relative position of child nodes. But as the tree grows, the nodes start to overlap if I use a fixed shift. I'm able to get around this by manually specifying the location of children nodes. But is there a better way to do it?

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,arrows,fit,matrix,positioning}
\tikzset
{
treenode/.style = {circle, draw=black, align=center, minimum size=1cm},
subtree/.style  = {isosceles triangle, draw=black, align=center, minimum height=0.5cm, minimum width=0.5cm, shape border rotate=90, anchor=north},
process/.style={rectangle, minimum width=2cm, minimum height=1cm, align=center, text width=2cm, draw},
connector/.style={circle, minimum size=1cm, align=center, text width=0.5cm, draw},
arrow/.style={thick, ->, >=stealth}
}
\usepackage{circuitikz}
\begin{document}
\begin{tikzpicture}
\newcommand\xShift{1.5}
\newcommand\yShift{1}
\node(x) [treenode] at (0, 0) {100};
\node(xl) [treenode] at ([shift=({-\xShift,-\yShift})]x) {50};
\node(xr) [treenode] at ([shift=({\xShift,-\yShift})]x) {200};
\node(xll) [treenode] at ([shift=({-\xShift,-\yShift})]xl) {25};
\node(xlr) [treenode] at ([shift=({\xShift,-\yShift})]xl) {70};
\node(xlll) [ground] at ([shift=({-\xShift,-\yShift})]xll) {};
\node(xllr) [subtree] at ([shift=({\xShift,-\yShift})]xll) {};
\node(xlrl) [treenode] at ([shift=({-\xShift,-\yShift})]xlr) {60};
\node(xlrr) [subtree] at ([shift=({\xShift,-\yShift})]xlr) {};
\draw[->] (x) -- (xl);
\draw[->] (x) -- (xr);
\draw[->] (xl) -- (xll);
\draw[->] (xl) -- (xlr);
\draw[->] (xll) -- (xlll);
\draw[->] (xll) -- (xllr.north);
\draw[->] (xlr) -- (xlrl);
\draw[->] (xlr) -- (xlrr.north);
\end{tikzpicture}
\end{document}


Related question Draw a binary tree using tikz

• Use graphdrawing library and run with lualatex Nov 3 '14 at 21:36
• thank you. I tried using it. But since I have three different shapes, it doesn't come out clean. For example, to connect 25 and its right subtree which is a triangle, I'm not able to specify that the arrow should be on the north of the triangle. Nov 3 '14 at 22:08

You might try using a matrix of nodes:

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{shapes.geometric,matrix}
\tikzset
{
treenode/.style = {circle, draw=black, align=center, text centered, minimum size=1cm},
subtree/.style  = {isosceles triangle, draw=black, align=center, minimum height=0.5cm, minimum width=0.5cm, shape border rotate=90},
phantom/.style = {draw=none, minimum size=0pt, inner sep=0pt, outer sep=0pt},
}
\usepackage{circuitikz}
\begin{document}
\begin{tikzpicture}
\matrix (mat) [matrix of nodes, nodes={treenode}]
{
&[5mm] &[5mm] &[5mm] 100 &[5mm] \\[5mm]
& & 50 & & 200 \\[5mm]
& 25 & & 70 & \\[5mm]
|[phantom]| {} & & 60 & &  |[subtree]| {} \\
& & |[subtree]| {} & &\\
};
\node [ground] at (mat-4-1) {};
\begin{scope}[draw, ->]
\draw (mat-1-4) -- (mat-2-3);
\draw (mat-1-4) -- (mat-2-5);
\draw (mat-2-3) -- (mat-3-2);
\draw (mat-3-2) -- (mat-4-3);
\draw (mat-2-3) -- (mat-3-4);
\draw (mat-3-4) -- (mat-4-3);
\draw (mat-3-4) -- (mat-4-5.north);
\draw (mat-3-2) -- (mat-4-1.north);
\end{scope}
\end{tikzpicture}
\end{document}


# EDIT

In response to the correction in the comment: in this case you could just adjust the matrix accordingly. However, I would probably draw a tree in this case instead. For example:

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{shapes.geometric}
\usepackage{forest}
\usepackage{circuitikz}
\begin{document}
\tikzset{/forest,
subtree/.style={isosceles triangle, draw=black, align=center, minimum height=0.5cm, minimum width=0.5cm, shape border rotate=90, child anchor=north, anchor=north, tier=terminus},
terminus/.style={draw=none, inner sep=0pt, outer sep=0pt, minimum height=0pt, minimum width=0pt, tier=terminus},
}
\begin{forest}
for tree={
edge path={
\noexpand\path [->, \forestoption{edge}] (!u.parent anchor) -- (.child anchor) \forestoption{edge label};
},
calign=fixed edge angles,
calign angle=45,
circle,
draw=black,
align=center,
text centered,
minimum size=10mm,
}
[100
[50
[25
[, terminus, name=ground here]
[, subtree]
]
[70
[60]
[, subtree]
]
]
[200
]
]
\node [ground] at (ground here) {};
\end{forest}
\end{document}


• I apologize for being not clear. The right child of 25 is a subtree and the left child of 70 is a node with value 60. I do not want them to overlap. Nov 3 '14 at 23:11
• @arunmoezhi Hmm... yes, that would have been easier. See my update. The revised question is more straightforward: I'd assumed that the problem was needing nodes with multiple parents. If you don't need that, a tree is the simplest solution, I think.
– cfr
Nov 3 '14 at 23:57