Skip to content

Commit 6b15c28

Browse files
authored
Merge pull request #27 from phyrwork/breadth-first-max-depth
Add max depth parameter to breadth first search
2 parents 9a1ba15 + d0b49da commit 6b15c28

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

src/Search/BreadthFirst.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,43 @@
99
class BreadthFirst extends Base
1010
{
1111
/**
12-
*
12+
* @param int $maxDepth
1313
* @return Vertices
1414
*/
15-
public function getVertices()
15+
public function getVertices($maxDepth = PHP_INT_MAX)
1616
{
1717
$queue = array($this->vertex);
1818
// to not add vertices twice in array visited
1919
$mark = array($this->vertex->getId() => true);
2020
// visited vertices
2121
$visited = array();
2222

23+
// keep track of depth
24+
$currentDepth = 0;
25+
$nodesThisLevel = 1;
26+
$nodesNextLevel = 0;
27+
2328
do {
2429
// get first from queue
2530
$t = array_shift($queue);
2631
// save as visited
27-
$visited[$t->getId()]= $t;
32+
$visited[$t->getId()] = $t;
2833

2934
// get next vertices
30-
foreach ($this->getVerticesAdjacent($t)->getMap() as $id => $vertex) {
35+
$children = $this->getVerticesAdjacent($t);
36+
37+
// track depth
38+
$nodesNextLevel = $children->count();
39+
if (--$nodesThisLevel === 0) {
40+
if (++$currentDepth > $maxDepth) {
41+
return new Vertices($visited);
42+
}
43+
$nodesThisLevel = $nodesNextLevel;
44+
$nodesNextLevel = 0;
45+
}
46+
47+
// process next vertices
48+
foreach ($children->getMap() as $id => $vertex) {
3149
// if not "touched" before
3250
if (!isset($mark[$id])) {
3351
// add to queue
@@ -37,7 +55,7 @@ public function getVertices()
3755
}
3856
}
3957

40-
// untill queue is empty
58+
// until queue is empty
4159
} while ($queue);
4260

4361
return new Vertices($visited);

tests/Search/BreadthFirstTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
use Fhaculty\Graph\Graph;
4+
use Graphp\Algorithms\Search\BreadthFirst;
5+
6+
class BreadthFirstSearchTest extends TestCase
7+
{
8+
public function providerMaxDepth()
9+
{
10+
return array(
11+
"simple path (no limit)" => array(
12+
"edges" => array(
13+
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
14+
),
15+
"subject" => 1,
16+
"maxDepth" => null,
17+
"expected" => array(1, 2, 3, 4, 5),
18+
),
19+
"simple path (limit = 0)" => array(
20+
"edges" => array(
21+
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
22+
),
23+
"subject" => 1,
24+
"maxDepth" => 0,
25+
"expected" => array(1),
26+
),
27+
"simple path (limit = 1)" => array(
28+
"edges" => array(
29+
array(1, 2), array(2, 3), array(3, 4), array(4, 5),
30+
),
31+
"subject" => 1,
32+
"maxDepth" => 1,
33+
"expected" => array(1, 2),
34+
),
35+
);
36+
}
37+
38+
/**
39+
* @dataProvider providerMaxDepth
40+
*/
41+
public function testMaxDepth(array $edges, $subject, $maxDepth, array $expected)
42+
{
43+
$g = new Graph();
44+
foreach ($edges as $e) {
45+
$g->createVertex($e[0], true)->createEdgeTo($g->createVertex($e[1], true));
46+
}
47+
$a = new BreadthFirst($g->getVertex($subject));
48+
if ($maxDepth !== null) {
49+
$v = $a->getVertices($maxDepth);
50+
} else {
51+
$v = $a->getVertices(); // Simulate default
52+
}
53+
$this->assertSame($expected, $v->getIds());
54+
}
55+
}

0 commit comments

Comments
 (0)