Skip to content

Commit 055096b

Browse files
committed
topological sorting, bitvectors, stack/queue improvement and bug fixes
1 parent 8a413e7 commit 055096b

22 files changed

+856
-213
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
/**
3+
* MIT License
4+
*
5+
* Copyright (c) 2018 Dogan Ucar
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in all
15+
* copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
* SOFTWARE.
24+
*/
25+
26+
namespace doganoo\PHPAlgorithms\Algorithm\Sorting;
27+
28+
29+
use doganoo\PHPAlgorithms\Common\Abstracts\AbstractGraph;
30+
use doganoo\PHPAlgorithms\Common\Exception\InvalidGraphTypeException;
31+
use doganoo\PHPAlgorithms\Common\Interfaces\IGraphSortable;
32+
use doganoo\PHPAlgorithms\Datastructure\Graph\Graph\DirectedGraph;
33+
use doganoo\PHPAlgorithms\Datastructure\Graph\Graph\Node;
34+
use doganoo\PHPAlgorithms\Datastructure\Lists\ArrayLists\ArrayList;
35+
use doganoo\PHPAlgorithms\Datastructure\Stackqueue\Stack;
36+
37+
/**
38+
* Class TopologicalSort
39+
*
40+
* @package doganoo\PHPAlgorithms\Algorithm\Sorting
41+
*/
42+
class TopologicalSort implements IGraphSortable {
43+
44+
/**
45+
* @param AbstractGraph $graph
46+
* @return Stack
47+
* @throws \doganoo\PHPAlgorithms\common\Exception\InvalidKeyTypeException
48+
* @throws \doganoo\PHPAlgorithms\common\Exception\UnsupportedKeyTypeException
49+
* @throws InvalidGraphTypeException
50+
*/
51+
public function sort(AbstractGraph $graph): Stack {
52+
if (!$graph instanceof DirectedGraph) {
53+
throw new InvalidGraphTypeException("topological sorting is only valid for directed graphs");
54+
}
55+
if ($graph->hasCycle()) {
56+
throw new InvalidGraphTypeException("the graph has a cycle. Topological sorting is only possible for directed acyclic graphs");
57+
}
58+
$allNodes = $graph->getNodes();
59+
$result = new Stack();
60+
$visited = new ArrayList();
61+
62+
/*
63+
* starting with any node, it is first necessary to determine
64+
* whether the node is already visited. If not, a helper method is
65+
* called, which has the business logic.
66+
*/
67+
/** @var Node $node */
68+
foreach ($allNodes as $node) {
69+
/*
70+
* skip node if it is already visited. Notice
71+
* that $visited and $result are passed by reference
72+
*/
73+
if ($visited->containsValue($node)) continue;
74+
$this->_sort($node, $result, $visited);
75+
}
76+
return $result;
77+
}
78+
79+
/**
80+
* @param Node $node
81+
* @param Stack $result
82+
* @param ArrayList $visited
83+
* @return void
84+
* @throws InvalidGraphTypeException
85+
* @throws \doganoo\PHPAlgorithms\common\Exception\InvalidKeyTypeException
86+
* @throws \doganoo\PHPAlgorithms\common\Exception\UnsupportedKeyTypeException
87+
*/
88+
private function _sort(Node $node, Stack &$result, ArrayList &$visited): void {
89+
$visited->add($node);
90+
/*
91+
* continue with the adjacent nodes of $node. The method calls itself
92+
* recursively until there are no nodes (the node is a leaf). Then,
93+
* the node is added to the stack (which is passed by reference)
94+
*/
95+
/** @var Node $adjacent */
96+
foreach ($node->getAdjacents() as $adjacent) {
97+
//skip if already visited
98+
if ($visited->containsValue($adjacent)) continue;
99+
//recursive call with the adjacent node of $node
100+
$this->_sort($adjacent, $result, $visited);
101+
}
102+
//add node to result stack
103+
$result->push($node);
104+
}
105+
}

src/Algorithm/Various/Permutation.php

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,18 @@ public function stringPermutations(string $string): array {
5050
$result[] = $string;
5151
return $result;
5252
}
53-
5453
$array = StringUtil::stringToArray($string);
54+
5555
$result = $this->permute($array, "", $result);
5656
return $result;
5757
}
5858

5959
/**
6060
* returns all permutations of an given array of objects
6161
*
62-
* @param array $objects
63-
* @param $prefix
64-
* @param array $result
62+
* @param array $objects
63+
* @param $prefix
64+
* @param array $result
6565
* @return array
6666
*/
6767
private function permute(array $objects, $prefix, array $result) {
@@ -71,30 +71,33 @@ private function permute(array $objects, $prefix, array $result) {
7171
//added to the array
7272
if (0 === $length) {
7373
$result[] = $prefix;
74+
return $result;
7475
}
7576
//if the number of elements in the array
7677
//is greater than 0, there are more elements
7778
//to build an permutation.
78-
else {
79-
//The length is decreased by each recursive function call
80-
for ($i = 0; $i < $length; $i++) {
81-
//a new prefix is created. The prefix consists of the
82-
//actual prefix ("" at the beginning) and the next element
83-
//in the objects array
84-
$newPrefix = $prefix . $objects[$i];
79+
// --------------------------------
80+
//The length is decreased by each recursive function call
81+
for ($i = 0; $i < $length; $i++) {
82+
//new object in order to create the new prefix
83+
$object = $objects[$i];
84+
85+
//a new prefix is created. The prefix consists of the
86+
//actual prefix ("" at the beginning) and the next element
87+
//in the objects array
88+
$newPrefix = $prefix . $object;
8589

86-
//since the ith element in objects is used as a prefix,
87-
//the remaining objects have to be sliced by exactly this
88-
//object in order to prevent a reoccurrence of the element in
89-
//the permutation
90-
$newObjects = \array_merge(
91-
\array_slice($objects, 0, $i),
92-
\array_slice($objects, $i + 1)
93-
);
90+
//since the ith element in objects is used as a prefix,
91+
//the remaining objects have to be sliced by exactly this
92+
//object in order to prevent a reoccurrence of the element in
93+
//the permutation
94+
$newObjects = \array_merge(
95+
\array_slice($objects, 0, $i),
96+
\array_slice($objects, $i + 1)
97+
);
9498

95-
//call the permute method with the new prefix and objects
96-
$result = $this->permute($newObjects, $newPrefix, $result);
97-
}
99+
//call the permute method with the new prefix and objects
100+
$result = $this->permute($newObjects, $newPrefix, $result);
98101
}
99102
return $result;
100103
}

src/Common/Abstracts/AbstractSet.php renamed to src/Common/Abstracts/AbstractISet.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
namespace doganoo\PHPAlgorithms\Common\Abstracts;
2727

2828

29-
use doganoo\PHPAlgorithms\Common\Interfaces\Set;
29+
use doganoo\PHPAlgorithms\Common\Interfaces\ISet;
3030

3131
/**
3232
* Class AbstractSet
3333
*
3434
* @package doganoo\PHPAlgorithms\Common\Abstracts
3535
*/
36-
abstract class AbstractSet implements Set {
36+
abstract class AbstractISet implements ISet {
3737
/**
3838
* Compares the specified object with this set for equality.
3939
*

0 commit comments

Comments
 (0)