Skip to content

Commit 0513d3d

Browse files
committed
Improve tree documentation
1 parent 7996792 commit 0513d3d

File tree

5 files changed

+149
-11
lines changed

5 files changed

+149
-11
lines changed

src/Tree/Base.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,27 @@
1010
use Fhaculty\Graph\Algorithm\Search\StrictDepthFirst;
1111

1212
/**
13+
* Abstract base class for tree algorithms
14+
*
15+
* This abstract base class provides the base interface for working with
16+
* graphs that represent a tree.
17+
*
18+
* A tree is a connected Graph (single component) with no cycles. Every Tree is
19+
* a Graph, but not every Graph is a Tree.
20+
*
21+
* A
22+
* / \
23+
* B C
24+
* / \
25+
* D E
26+
*
27+
* Special cases are undirected trees (like the one pictured above), handled via
28+
* Tree\Undirected and directed, rooted trees (InTree and OutTree), handled via
29+
* Tree\BaseDirected.
1330
*
1431
* @link http://en.wikipedia.org/wiki/Tree_%28graph_theory%29
15-
* @see OutTree
16-
* @see InTree
32+
* @see Undirected for an implementation of these algorithms on (undirected) trees
33+
* @see BaseDirected for an abstract implementation of these algorithms on directed, rooted trees
1734
*/
1835
abstract class Base extends BaseGraph
1936
{
@@ -25,15 +42,19 @@ abstract class Base extends BaseGraph
2542
abstract public function isTree();
2643

2744
/**
28-
* checks if the given $vertex is a leaf (outermost vertex / leaf node / external node / terminal node)
45+
* checks if the given $vertex is a leaf (outermost vertext)
46+
*
47+
* leaf vertex is also known as leaf node, external node or terminal node
2948
*
3049
* @param Vertex $vertex
3150
* @return boolean
3251
*/
3352
abstract public function isVertexLeaf(Vertex $vertex);
3453

3554
/**
36-
* checks if the given $vertex is an internal vertex (inner node / inode / branch node / somewhere in the "middle" of the tree)
55+
* checks if the given $vertex is an internal vertex (somewhere in the "middle" of the tree)
56+
*
57+
* internal vertex is also known as inner node (inode) or branch node
3758
*
3859
* @param Vertex $vertex
3960
* @return boolean

src/Tree/BaseDirected.php

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,45 @@
88
use Fhaculty\Graph\Vertex;
99

1010
/**
11+
* Abstract algorithm base class for working with directed, rooted trees
1112
*
13+
* Directed trees have an designated root Vertex, which is the uppermost Vertex.
14+
* Every other Vertex is either a directed child of this root Vertex or an
15+
* indirect descendant (recursive child).
16+
*
17+
* There are two common implementations of directed trees:
18+
*
19+
* - Usual OutTree implementation where Edges "point away" from root Vertex
20+
*
21+
* ROOT
22+
* / \
23+
* A <--/ \--> B
24+
* \
25+
* \--> C
26+
*
27+
* - Alternative InTree implementation where Edges "point towards" root Vertex
28+
*
29+
* ROOT
30+
* ^ ^
31+
* / \
32+
* A B
33+
* ^
34+
* \
35+
* C
36+
*
37+
* It's your choice on how to direct the edges, but make sure they all point in
38+
* the "same direction", or it will not be a valid tree anymore. However your
39+
* decision may be, in the above example, ROOT is always the root Vertex,
40+
* B is the parent of "C" and A, B are the children of ROOT.
41+
*
42+
* For performance reasons, except for `isTree()`, none of the below methods
43+
* check if the given Graph is actually a valid tree. So make sure to verify
44+
* `isTree()` returns `true` before relying on any of the methods.
45+
*
46+
* @link http://en.wikipedia.org/wiki/Arborescence_%28graph_theory%29
1247
* @link http://en.wikipedia.org/wiki/Spaghetti_stack
13-
* @see OutTree
48+
* @see OutTree usual implementation where Edges "point away" from root vertex
49+
* @see InTree alternative implementation where Edges "point towards" root vertex
1450
*/
1551
abstract class BaseDirected extends Tree
1652
{
@@ -19,6 +55,8 @@ abstract class BaseDirected extends Tree
1955
*
2056
* @return Vertex
2157
* @throws UnderflowException if given graph is empty or no possible root candidate was found (check isTree()!)
58+
* @uses Graph::getVertices() to iterate over each Vertex
59+
* @uses self::isVertexPossibleRoot() to check if any Vertex is a possible root candidate
2260
*/
2361
public function getVertexRoot()
2462
{
@@ -34,8 +72,9 @@ public function getVertexRoot()
3472
* checks if this is a tree
3573
*
3674
* @return boolean
37-
* @uses Graph::isEmpty()
38-
* @uses self::getVertexRoot() to actually check tree
75+
* @uses Graph::isEmpty() to skip empty Graphs (an empty is Graph is a valid tree)
76+
* @uses self::getVertexRoot() to get root Vertex to start search from
77+
* @uses self::getVerticesSubtree() to count number of vertices connected to root
3978
*/
4079
public function isTree()
4180
{
@@ -60,6 +99,7 @@ public function isTree()
6099
return false;
61100
}
62101

102+
// check number of vertices reachable from root should match total number of vertices
63103
return ($num === $this->graph->getNumberOfVertices());
64104
}
65105

@@ -70,6 +110,7 @@ public function isTree()
70110
* @throws UnderflowException if vertex has no parent (is a root vertex)
71111
* @throws UnexpectedValueException if vertex has more than one possible parent (check isTree()!)
72112
* @return Vertex
113+
* @uses self::getVerticesParents() to get array of parent vertices
73114
*/
74115
public function getVertexParent(Vertex $vertex)
75116
{
@@ -93,8 +134,24 @@ public function getVertexParent(Vertex $vertex)
93134
*/
94135
abstract public function getVerticesChildren(Vertex $vertex);
95136

137+
/**
138+
* internal helper to get all parents vertices
139+
*
140+
* a valid tree vertex only ever has a single parent, expect for the root,
141+
* which has none.
142+
*
143+
* @param Vertex $vertex
144+
* @return Vertex[]
145+
*/
96146
abstract protected function getVerticesParent(Vertex $vertex);
97147

148+
/**
149+
* check if given vertex is a possible root (i.e. has no parent)
150+
*
151+
* @param Vertex $vertex
152+
* @return boolean
153+
* @uses self::getVerticesParent()
154+
*/
98155
protected function isVertexPossibleRoot(Vertex $vertex)
99156
{
100157
return (count($this->getVerticesParent($vertex)) === 0);
@@ -105,13 +162,22 @@ protected function isVertexPossibleRoot(Vertex $vertex)
105162
*
106163
* @param Vertex $vertex
107164
* @return boolean
108-
* @uses self::getVerticesChildren()
165+
* @uses self::getVerticesChildren() to check given vertex has no children
109166
*/
110167
public function isVertexLeaf(Vertex $vertex)
111168
{
112169
return (count($this->getVerticesChildren($vertex)) === 0);
113170
}
114171

172+
/**
173+
* checks if the given $vertex is an internal vertex (has children and is not root)
174+
*
175+
* @param Vertex $vertex
176+
* @return boolean
177+
* @uses self::getVerticesParent() to check given vertex has a parent (is not root)
178+
* @uses self::getVerticesChildren() to check given vertex has children (is not a leaf)
179+
* @see \Fhaculty\Graph\Algorithm\Tree\Base::isVertexInternal() for more information
180+
*/
115181
public function isVertexInternal(Vertex $vertex)
116182
{
117183
return ($this->getVerticesParent($vertex) && $this->getVerticesChildren($vertex));

src/Tree/InTree.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,18 @@
77
use Fhaculty\Graph\Vertex;
88

99
/**
10+
* Alternative InTree implementation where Edges "point towards" root Vertex
11+
*
12+
* ROOT
13+
* ^ ^
14+
* / \
15+
* A B
16+
* ^
17+
* \
18+
* C
1019
*
1120
* @link http://en.wikipedia.org/wiki/Spaghetti_stack
12-
* @see OutTree
21+
* @see DirectedTree for more information on directed, rooted trees
1322
*/
1423
class InTree extends DirectedTree
1524
{

src/Tree/OutTree.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@
77
use Fhaculty\Graph\Vertex;
88

99
/**
10-
* A rooted tree with the "away from root" direction (a more narrow term is an "arborescence"), meaning:
10+
* Usual OutTree implementation where Edges "point away" from root Vertex
11+
*
12+
* ROOT
13+
* / \
14+
* A <--/ \--> B
15+
* \
16+
* \--> C
17+
*
18+
* also known as arborescence
1119
*
1220
* @link http://en.wikipedia.org/wiki/Arborescence_%28graph_theory%29
13-
* @see InTree
21+
* @see DirectedTree for more information on directed, rooted trees
1422
*/
1523
class OutTree extends DirectedTree
1624
{

src/Tree/Undirected.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,34 @@
1010
use Fhaculty\Graph\Vertex;
1111

1212
/**
13+
* Undirected tree implementation
1314
*
15+
* An undirected tree is a connected Graph (single component) with no cycles.
16+
* Every undirected Tree is an undirected Graph, but not every undirected Graph
17+
* is an undirected Tree.
18+
*
19+
* A
20+
* / \
21+
* B C
22+
* / \
23+
* D E
24+
*
25+
* Undirected trees do not have special root Vertices (like the above picture
26+
* might suggest). The above tree Graph can also be equivalently be pictured
27+
* like this:
28+
*
29+
* C
30+
* /|\
31+
* / | \
32+
* A D E
33+
* /
34+
* B
35+
*
36+
* If you're looking for a tree with a designated root Vertex, use directed,
37+
* rooted trees (BaseDirected).
38+
*
39+
* @link http://en.wikipedia.org/wiki/Tree_%28graph_theory%29
40+
* @see BaseDirected if you're looking for directed, rooted trees
1441
*/
1542
class Undirected extends Tree
1643
{
@@ -41,6 +68,13 @@ public function isVertexLeaf(Vertex $vertex)
4168
return ($vertex->getDegree() === 1);
4269
}
4370

71+
/**
72+
* checks if the given $vertex is an internal vertex (inner vertex with at least 2 edges)
73+
*
74+
* @param Vertex $vertex
75+
* @return boolean
76+
* @uses Vertex::getDegree()
77+
*/
4478
public function isVertexInternal(Vertex $vertex)
4579
{
4680
return ($vertex->getDegree() >= 2);

0 commit comments

Comments
 (0)