The implementation of the shortest path finding algorithm (dixstra algorithm) in php

Keywords: Python PHP

Refer to Chapter 7 of algorithm diagram for details. The original book was written in python, and I wrote it again in PHP, which was slightly improved

Test these three exercises in the book

 

I found another "difficult" question on the Internet

 

Upper Code:

class ShortPath{
    protected $graph=[];//A graph can be represented only by storing the neighbors corresponding to each node

    protected $parents=[];//Save the parent relationship, and finally backtrack the shortest path through this array

    protected $costs;//Cost from start to each node

    protected $infinity=999999;//Use a large number to represent a positive infinity

    protected $processed=[];//key of processed node


    public function __construct($graph)
    {
        $this->graph=$graph;

        //Initialize the parent array, that is, only the neighbors of start are known, that is, the parent of start
        foreach ($this->graph['start'] as $k=>$v) {
            $this->parents[$k]='start';
        }

        //Initialize the cost array, that is, only the cost of the neighbor node of start is known, and all other nodes are positive infinite
        foreach ($this->graph as $k=>$v) {
            if($k=='start'){
                $this->costs=$this->graph['start'];
            }elseif(empty($this->costs[$k])){
                $this->costs[$k]=$this->infinity;
            }
        }
        $this->costs['finish']=$this->infinity;
    }

    public function find(){
        $nodeKey=$this->findLowestCostNode($this->costs);
        while ($nodeKey){//As long as there are unprocessed nodes
            $cost=$this->costs[$nodeKey];
            $neighbors=$this->graph[$nodeKey] ?? [];//Take neighbors
            //Traversing neighbors
            foreach ($neighbors as $k=> $v) {
                $newCost=$cost+$v;
                if($this->costs[$k] > $newCost){
                    $this->costs[$k]=$newCost;//Update lower overhead
                    $this->parents[$k]=$nodeKey;
                }
            }

            //Debug output
            echo 'Current node:' .$nodeKey . PHP_EOL;
            echo 'Neighbours:' . PHP_EOL;
            print_r($neighbors);
            echo 'Expenses:' . PHP_EOL;
            print_r($this->costs);

            //Now that all neighbors of the node have been processed, mark the node as processed
            $this->processed[]=$nodeKey;
            //Find the next node to be processed
            $nodeKey=$this->findLowestCostNode();
        }
        $this->showResult();
    }

    //Find the shortest one among the unprocessed nodes
    protected function findLowestCostNode(){
        $lowestCost=$this->infinity;//Set positive infinity here so that when you first enter the loop, it must be larger than the first element
        $lowestCostKey=false;//The key of the shortest path node to return
        foreach ($this->costs as $k=>$v) {
            if($v<$lowestCost && !in_array($k,$this->processed)){
                $lowestCost=$v;
                $lowestCostKey=$k;
            }
        }
        return $lowestCostKey;
    }

    //Beautify display processing results
    protected function showResult(){
        $path=[];
        $key='finish';
        //From the end, find the parent and trace back the shortest route
        while (isset($this->parents[$key])){
            array_unshift($path,$key);
            $key=$this->parents[$key];
        }
        echo 'The shortest path length is:' . $this->costs['finish'] . PHP_EOL;
        echo 'The route is:start->' . implode('->',$path) . PHP_EOL;
    }

}

//Corresponding exercise A
$graph1=[
    "start"=>[
        "a"=>2,
        "b"=>5,
    ],
    "a"=>[
        "b"=>8,
        "d"=>7,
    ],
    "b"=>[
        "c"=>4,
        "d"=>2,
    ],
    "c"=>[
        "finish"=>3,
        "d"=>6
    ],
    "d"=>[
        "finish"=>1
    ]
];

//Corresponding Exercise B
$graph2=[
    "start"=>[
        "a"=>10,
    ],
    "a"=>[
        "c"=>20,
    ],
    "b"=>[
        "a"=>1,
    ],
    "c"=>[
        "b"=>1,
        "finish"=>30,
    ],
];


//Corresponding exercise C. It can be seen that the algorithm is not suitable for the case with negative weight edges
$graph3=[
    "start"=>[
        "a"=>2,
        "b"=>2,
    ],
    "a"=>[
        "c"=>2,
        "finish"=>2
    ],
    "b"=>[
        "a"=>2,
    ],
    "c"=>[
        "b"=>-100,
        "finish"=>2,
    ],
];

//Corresponding to the last question, change v0 in the figure to start and v8 to finish
$graph4=[
    "start"=>[
        "v1"=>1,
        "v2"=>5,
    ],
    "v1"=>[
        "start"=>1,
        "v2"=>3,
        "v3"=>7,
        "v4"=>5,
    ],
    "v2"=>[
        "start"=>5,
        "v1"=>3,
        "v4"=>1,
    ],
    "v3"=>[
        "v1"=>7,
        "v2"=>2,
        "v6"=>3,
    ],
    "v4"=>[
        "v1"=>5,
        "v2"=>1,
        "v3"=>2,
        "v5"=>3,
        "v6"=>6,
        "v7"=>9,
    ],
    "v5"=>[
        "v2"=>6,
        "v4"=>3,
        "v7"=>5,
    ],
    "v6"=>[
        "v3"=>3,
        "v4"=>6,
        "v7"=>2,
        "finish"=>7
    ],
    "v7"=>[
        "v4"=>9,
        "v5"=>5,
        "v6"=>2,
        "finish"=>4
    ],
];

$obj=new ShortPath($graph4);
$obj->find();

Output of the last question

 

Finally, the pdf version of the book "algorithm diagram" is attached

Link: https://pan.baidu.com/s/1nditk7wayn7c9fz3ldngw password: ij0r

Published 18 original articles, won praise 15, visited 40000+
Private letter follow

Posted by Pioden on Wed, 05 Feb 2020 07:13:55 -0800