94 lines
2.4 KiB
PHP
94 lines
2.4 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Graphp\Algorithms\TravelingSalesmanProblem;
|
||
|
|
||
|
use Fhaculty\Graph\Exception\UnexpectedValueException;
|
||
|
|
||
|
use Fhaculty\Graph\Vertex;
|
||
|
use Fhaculty\Graph\Edge\Base as Edge;
|
||
|
use Fhaculty\Graph\Set\Edges;
|
||
|
use \SplPriorityQueue;
|
||
|
|
||
|
class NearestNeighbor extends Base4
|
||
|
{
|
||
|
/**
|
||
|
*
|
||
|
* @var Vertex
|
||
|
*/
|
||
|
private $vertex;
|
||
|
|
||
|
public function __construct(Vertex $startVertex)
|
||
|
{
|
||
|
$this->vertex = $startVertex;
|
||
|
}
|
||
|
|
||
|
protected function getVertexStart()
|
||
|
{
|
||
|
return $this->vertex;
|
||
|
}
|
||
|
|
||
|
protected function getGraph()
|
||
|
{
|
||
|
return $this->vertex->getGraph();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @return Edges
|
||
|
*/
|
||
|
public function getEdges()
|
||
|
{
|
||
|
$returnEdges = array();
|
||
|
|
||
|
$n = count($this->vertex->getGraph()->getVertices());
|
||
|
|
||
|
$vertex = $this->vertex;
|
||
|
$visitedVertices = array($vertex->getId() => true);
|
||
|
|
||
|
for ($i = 0; $i < $n - 1; ++$i,
|
||
|
// n-1 steps (spanning tree)
|
||
|
$vertex = $nextVertex) {
|
||
|
|
||
|
// get all edges from the aktuel vertex
|
||
|
$edges = $vertex->getEdgesOut();
|
||
|
|
||
|
$sortedEdges = new SplPriorityQueue();
|
||
|
|
||
|
// sort the edges
|
||
|
foreach ($edges as $edge) {
|
||
|
$sortedEdges->insert($edge, - $edge->getWeight());
|
||
|
}
|
||
|
|
||
|
// Untill first is found: get cheepest edge
|
||
|
foreach ($sortedEdges as $edge) {
|
||
|
|
||
|
// Get EndVertex of this edge
|
||
|
$nextVertex = $edge->getVertexToFrom($vertex);
|
||
|
|
||
|
// is unvisited
|
||
|
if (!isset($visitedVertices[$nextVertex->getId()])) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check if there is a way i can use
|
||
|
if (isset($visitedVertices[$nextVertex->getId()])) {
|
||
|
throw new UnexpectedValueException('Graph is not complete - can\'t find an edge to unconnected vertex');
|
||
|
}
|
||
|
|
||
|
$visitedVertices[$nextVertex->getId()] = TRUE;
|
||
|
|
||
|
// clone edge in new Graph
|
||
|
$returnEdges []= $edge;
|
||
|
|
||
|
}
|
||
|
|
||
|
// check if there is a way from end edge to start edge
|
||
|
// get first connecting edge
|
||
|
// connect the last vertex with the start vertex
|
||
|
$returnEdges []= $vertex->getEdgesTo($this->vertex)->getEdgeFirst();
|
||
|
|
||
|
return new Edges($returnEdges);
|
||
|
}
|
||
|
}
|