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
+ }
0 commit comments