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