1.核心文件(service)
namespace app\Http\Services;
class Dijkstra2Service
{
protected $graph=[];//只需要存每个节点所对应的邻居们,就能表示一个图了
protected $parents=[];//保存父级关系,最终能通过这个数组,回溯走过的最短路线
protected $costs;//从起点,到每个节点的花销
protected $infinity=999999;//用一个很大的数字,来代表一个正无穷大
protected $processed=[];//已处理过的节点的key
protected $start;
protected $end;
public function __construct($graph,$start,$end)
{
$this->graph=$graph;
$this->start=$start;
$this->end=$end;
//初始化父级数组, 即:只知道start的邻居,就是start的父级
foreach ($this->graph[$this->start] as $k=>$v) {
$this->parents[$k]=$this->start;
}
//初始化花销数组,即:只知道start的邻居节点的花销,其它节点都是正无穷
foreach ($this->graph as $k=>$v) {
if($k==$this->start){
$this->costs=$this->graph[$this->start];
}elseif(empty($this->costs[$k])){
$this->costs[$k]=$this->infinity;
}
}
$this->costs[$end]=$this->infinity;
}
public function find(){
$nodeKey=$this->findLowestCostNode($this->costs);
while ($nodeKey){//只要还有未处理过的节点
$cost=$this->costs[$nodeKey];
$neighbors=$this->graph[$nodeKey] ?? [];//取邻居
//遍历邻居
foreach ($neighbors as $k=> $v) {
$newCost=$cost+$v;
if(isset($this->costs[$k]) && $this->costs[$k] > $newCost){
$this->costs[$k]=$newCost;//将更低的开销更新
$this->parents[$k]=$nodeKey;
}
}
//既然已处理完了该节点的所有邻居,那么将该节点标记为已处理过了
$this->processed[]=$nodeKey;
//找出下一个待处理的节点
$nodeKey=$this->findLowestCostNode();
}
return $this->showResult();
}
//在未处理过的节点中,查找出最短的那个
protected function findLowestCostNode(){
$lowestCost=$this->infinity;//在这里设置为正无穷是为了,在第一次进入循环时,必然比第一个元素大
$lowestCostKey=false;//要返回的最短路径节点的key
foreach ($this->costs as $k=>$v) {
if($vprocessed)){
$lowestCost=$v;
$lowestCostKey=$k;
}
}
return $lowestCostKey;
}
//美化显示处理结果
protected function showResult(){
$path=[];
$key=$this->end;
//从终点开始,查找父级,回溯出最短路线
while (isset($this->parents[$key])){
array_unshift($path,$key);
$key=$this->parents[$key];
}
$data=['count'=>'最短路径全长是:' . $this->costs[$this->end],'path'=>'路线是:'.$this->start.'->' . implode('->',$path)];
return $data;
}
}
2.控制器使用
namespace app\Http\Controllers\Api\Mini;
use App\Http\Services\Dijkstra2Service;
class TestController
{
public function testFindWeight()
{
$start="太白南路";
$end="新政中心";
$graph=[
"太白南路"=>[
"科技路"=>1,
"小寨"=>2,
],
"科技路"=>[
"西北工业大学"=>1,
"太白南路"=>1,
],
"西北工业大学"=>[
"科技路"=>1,
"南稍门"=>3,
],
"小寨"=>[
"南稍门"=>2,
"太白南路"=>2,
"大雁塔"=>1,
],
"南稍门"=>[
"小寨"=>2,
"西北工业大学"=>3,
"建筑科技大学"=>2,
"新政中心"=>10,
],
"建筑科技大学"=>[
"南稍门"=>2,
"新政中心"=>1,
],
];
//$graph正常从数据库读取,新数据拼接而成
$obj=new Dijkstra2Service($graph,$start,$end);
$data=$obj->find();
return $data;
}
}
3.最终结果
{
"count": "最短路径全长是:7",
"path": "路线是:太白南路->小寨->南稍门->建筑科技大学->新政中心"
}