diff --git a/composer.json b/composer.json index 5ff63df..3b25571 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,11 @@ "name": "Joonas Pajunen", "email": "joonas.pajunen@gmail.com", "role": "Developer" + }, + { + "name": "Martin Pärtel", + "email": "martin.partel@gmail.com", + "role": "Developer" } ], "require": { diff --git a/library/Xi/Algorithm/TopologicalSort.php b/library/Xi/Algorithm/TopologicalSort.php new file mode 100644 index 0000000..a8f687c --- /dev/null +++ b/library/Xi/Algorithm/TopologicalSort.php @@ -0,0 +1,76 @@ + $others) { + if (!is_array($others)) { + throw new \InvalidArgumentException('Dependencies should be given as arrays, not single elements.'); + } + $allNodes[] = $node; + foreach ($others as $other) { + $allNodes[] = $other; + } + } + + return array_unique($allNodes); + } +} diff --git a/tests/Xi/Tests/Algorithm/TopologicalSortTest.php b/tests/Xi/Tests/Algorithm/TopologicalSortTest.php new file mode 100644 index 0000000..daef859 --- /dev/null +++ b/tests/Xi/Tests/Algorithm/TopologicalSortTest.php @@ -0,0 +1,95 @@ + ['C', 'D'], + 'A' => ['B'], + 'C' => ['D'], + ]; + + for ($i = 0; $i < 100; ++$i) { + $edges = self::shuffleGraphSpec($edges); + $this->assertEquals(['D', 'C', 'B', 'A'], TopologicalSort::apply($edges)); + } + } + + /** + * @test + * @dataProvider provider + */ + public function test(array $edges) + { + for ($i = 0; $i < 100; ++$i) { + $edges = self::shuffleGraphSpec($edges); + $sorted = TopologicalSort::apply($edges); + $this->verify($sorted, $edges); + } + } + + public function provider() + { + return [ + [[ + 'B' => ['C', 'D'], + 'A' => ['B'], + 'C' => ['D'], + ]], + + // Wikipedia's example + [[ + 7 => [11, 8], + 5 => [11], + 3 => [8, 10], + 11 => [2, 9, 10], + 8 => [9] + ]] + ]; + } + + /** + * @test + * @expectedException \InvalidArgumentException + */ + public function throwsOnCycle() + { + $edges = [ + 'B' => ['C', 'D'], + 'A' => ['B'], + 'C' => ['D'], + 'D' => ['A'] + ]; + + TopologicalSort::apply($edges); + } + + private function shuffleGraphSpec(array $array) + { + $keys = array_keys($array); + shuffle($keys); + $result = []; + foreach ($keys as $key) { + $result[$key] = $array[$key]; + shuffle($result[$key]); + } + + return $result; + } + + private function verify(array $sorted, array $edges) + { + foreach ($edges as $left => $rights) { + foreach ($rights as $right) { + $leftIndex = array_search($left, $sorted); + $rightIndex = array_search($right, $sorted); + $this->assertLessThan($leftIndex, $rightIndex); + } + } + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8e9f38a..2598748 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,4 +5,4 @@ wget http://getcomposer.org/composer.phar php composer.phar install --dev "); -} \ No newline at end of file +}