programming-examples/php/Algo/Kruskal.php
2019-11-15 12:59:38 +01:00

135 lines
4.3 KiB
PHP

<?php
namespace Graphp\Algorithms\MinimumSpanningTree;
use Fhaculty\Graph\Exception\RuntimeException;
use Fhaculty\Graph\Exception\UnexpectedValueException;
use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Edge\Directed as EdgeDirected;
use Fhaculty\Graph\Set\Edges;
use \SplPriorityQueue;
class Kruskal extends Base
{
/**
*
* @var Graph
*/
private $graph;
public function __construct(Graph $inputGraph)
{
$this->graph = $inputGraph;
}
protected function getGraph()
{
return $this->graph;
}
/**
*
* @return Edges
*/
public function getEdges()
{
// Sortiere Kanten im Graphen
$sortedEdges = new SplPriorityQueue();
// For all edges
$this->addEdgesSorted($this->graph->getEdges(), $sortedEdges);
$returnEdges = array();
// next color to assign
$colorNext = 0;
// array(color1 => array(vid1, vid2, ...), color2=>...)
$colorVertices = array();
// array(vid1 => color1, vid2 => color1, ...)
$colorOfVertices = array();
// Füge billigste Kanten zu neuen Graphen hinzu und verschmelze teilgragen wenn es nötig ist (keine Kreise)
// solange ich mehr als einen Graphen habe mit weniger als n-1 kanten (bei n knoten im original)
foreach ($sortedEdges as $edge) {
/* @var $edge EdgeDirected */
// Gucke Kante an:
$vertices = $edge->getVertices()->getIds();
$aId = $vertices[0];
$bId = $vertices[1];
$aColor = isset($colorOfVertices[$aId]) ? $colorOfVertices[$aId] : NULL;
$bColor = isset($colorOfVertices[$bId]) ? $colorOfVertices[$bId] : NULL;
// 1. weder start noch end gehört zu einem graphen
// => neuer Graph mit kanten
if ($aColor === NULL && $bColor === NULL) {
$colorOfVertices[$aId] = $colorNext;
$colorOfVertices[$bId] = $colorNext;
$colorVertices[$colorNext] = array($aId, $bId);
++$colorNext;
// connect both vertices
$returnEdges []= $edge;
}
// 4. start xor end gehören zu einem graphen
// => erweitere diesesn Graphen
// Only b has color
else if ($aColor === NULL && $bColor !== NULL) {
// paint a in b's color
$colorOfVertices[$aId] = $bColor;
$colorVertices[$bColor][]=$aId;
$returnEdges []= $edge;
// Only a has color
} elseif ($aColor !== NULL && $bColor === NULL) {
// paint b in a's color
$colorOfVertices[$bId] = $aColor;
$colorVertices[$aColor][]=$bId;
$returnEdges []= $edge;
}
// 3. start und end gehören zu unterschiedlichen graphen
// => vereinigung
// Different color
else if ($aColor !== $bColor) {
$betterColor = $aColor;
$worseColor = $bColor;
// more vertices with color a => paint all in b in a's color
if (count($colorVertices[$bColor]) > count($colorVertices[$aColor])) {
$betterColor = $bColor;
$worseColor = $aColor;
}
// search all vertices with color b
foreach ($colorVertices[$worseColor] as $vid) {
$colorOfVertices[$vid] = $betterColor;
// repaint in a's color
$colorVertices[$betterColor][]=$vid;
}
// delete old color
unset($colorVertices[$worseColor]);
$returnEdges []= $edge;
}
// 2. start und end gehören zum gleichen graphen => zirkel
// => nichts machen
}
// definition of spanning tree: number of edges = number of vertices - 1
// above algorithm does not check isolated edges or may otherwise return multiple connected components => force check
if (count($returnEdges) !== (count($this->graph->getVertices()) - 1)) {
throw new UnexpectedValueException('Graph is not connected');
}
return new Edges($returnEdges);
}
}