<?php
define('I',100000); // define infinite distance
/**
* class to Build Dijkstra model
* To build the class
* Use int to index all the points on the map
* @param int startPoint
* @param array routes[] = array($startPoint,$endPoint,$distance)
* @author Rick.purple
*/
class Dijkstra{
private $intStartPoint;
private $aRoutes = array(); // all possible routes between each two points (single direction)
private $aPoints = array(); // all the points on the map
private $aReds = array();
private $aBlues = array();
private $aDistances = array(); // the closest distance from start point to each points
private $aPathes = array(); // path from each points to its neibor on the best path to the start point
private $aFullPathes; // path from start point to each points
/**
* Build Dijkstra model, find best path and closest distance from start point to each point on the map
* @return null
* @param object $intStartPoint
* @param object $aRoutes
*/
public function __construct($intStartPoint,$aRoutes){
$this->aRoutes = $aRoutes;
$this->intStartPoint = $intStartPoint;
foreach($aRoutes as $aRoute){
if(!in_array($aRoute[0],$this->aPoints)){
$this->aPoints[] = $aRoute[0];
}
if(!in_array($aRoute[1],$this->aPoints)){
$this->aPoints[] = $aRoute[1];
}
}
$this->aReds = array($intStartPoint);
$this->aBlues = $this->array_remove($this->aPoints, $intStartPoint);
foreach($this->aBlues as $intPoint){
$this->aDistances[$intPoint] = I;
}
$this->aDistances[$intStartPoint] = 0;
$this->findPath();
}
/**
* function to get the best path
* @return pathes for each node on the map
*/
public function getPath(){
foreach($this->aPoints as $intPoint){
$this->fillFullPath($intPoint,$intPoint);
}
return $this->aFullPathes;
}
/**
* function to get the closest distance
* @return
*/
public function getDistance(){
return $this->aDistances;
}
/**
* Remove specified element from array
* @return array
* @param array $arr : array to be processing
* @param array $value : the element to be remove from the array
*/
private function array_remove($arr,$value) {
return array_values(array_diff($arr,array($value)));
}
/**
* Dijkstra algorithm implementation
* @return null
*/
private function findPath(){
while(!empty($this->aBlues)){
$intShortest = I;
foreach($this->aReds as $intRed){
# find possible rounte
foreach($this->aRoutes as $aRoute){
if($intRed == $aRoute[0]){
$aDis[$intRed][$aRoute[1]] = $aRoute[2];
# rewrite distance
$intDistance = $this->aDistances[$intRed] + $aRoute[2];
if($this->aDistances[$aRoute[1]] > $intDistance){
$this->aDistances[$aRoute[1]] = $intDistance;
# change the path
if($intRed==$this->intStartPoint ||$intRed==$aRoute[1]){}
else{
$this->aPathes[$aRoute[1]] = $intRed;
}
}
# find the nearest neighbor
if(!in_array($aRoute[1],$this->aReds)&&$aRoute[2]<$intShortest){
$intShortest = $aRoute[2];
$intAddPoint = $aRoute[1];
}
}
}
}
$this->aReds[] = $intAddPoint;
$this->aBlues = $this->array_remove($this->aBlues, $intAddPoint);
}
}
/**
* mid step function to find full path from start point to the end point.
* @return null
* @param int $intEndPoint
* @param int $intMidPoint
*/
private function fillFullPath($intEndPoint,$intMidPoint){
if(isset($this->aPathes[$intMidPoint])){
$this->aFullPathes[$intEndPoint][] = $this->aPathes[$intMidPoint];
$this->fillFullPath($intEndPoint,$this->aPathes[$intMidPoint]);
}
else{
$this->aFullPathes[$intEndPoint][] = $this->intStartPoint;
}
}
}
# Examples
// single direction route path
$aRoutes = array(
array(0,0,0),
array(0,1,10),
array(0,3,30), // use something like array(3,0,20) to define a two way map
array(0,4,100),
array(1,1,0),
array(1,2,50),
array(2,2,0),
array(2,4,10),
array(3,3,0),
array(3,2,20),
array(3,4,60),
array(4,4,0),
);
$oDijk = new Dijkstra(0,$aRoutes); // startPoint = 0
print_r($oDijk->getPath());
print_r($oDijk->getDistance());
?>