Skip to content

Commit

Permalink
add Dijkstra algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
xx19941215 committed Oct 30, 2018
1 parent 0d12040 commit e234924
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 5 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,11 @@
- [广度优先遍历](dataStructure/Graph/Graph.php)
- [拓扑排序](dataStructure/Graph/Graph.php)
- [最短路径之Floyd算法](dataStructure/Graph/Graph.php)
- [单源最短路径Dijkstra算法](dataStructure/Graph/Graph.php)


#### 《剑指Offer》

> 先用PHP解答一遍,稍后Javascript版本的奉上
- 链表
- [从头到尾打印链表](offer/LinkedList/1.php)
- [链表中倒数第k个节点](offer/LinkedList/2.php)
Expand Down
53 changes: 52 additions & 1 deletion dataStructure/Graph/Graph.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php
namespace DataStructure\Graph;

use DataStructure\Spl\SplPriorityQueue;


class Graph
{
public static function BFS(&$graph, int $start, array $visited) : \SplQueue
Expand Down Expand Up @@ -152,7 +155,7 @@ protected static function topologicalSortV2(array $matrix): \SplQueue
return $sorted;
}

public static function FW(array $graph): array
public static function floydWarshall(array $graph): array
{
$dist = [];
$dist = $graph;
Expand All @@ -168,5 +171,53 @@ public static function FW(array $graph): array

return $dist;
}

public static function Dijkstra(array $graph, string $source, string $target)
{
$dist = [];
$prev = [];

$queue = new \SplPriorityQueue();

foreach ($graph as $vertex => $weight) {
$dist[$vertex] = PHP_INT_MAX;
$prev[$vertex] = null;
$queue->insert($vertex, min($weight));
}

$dist[$source] = 0;

while (!$queue->isEmpty()) {
$current = $queue->extract();

if (!empty($graph[$current])) {
foreach($graph[$current] as $vertex => $weight) {
//如果源点到$vertx的距离大于到源点到$current的距离再加上从$current到$vertex的距离
if ($dist[$current] + $weight < $dist[$vertex]) {
//修正源点到$vertex的最短距离
$dist[$vertex] = $dist[$current] + $weight;
//设置最短距离中的上一个节点
$prev[$vertex] = $current;
}
}
}
}

$stack = new \SplStack();
$distance = 0;

while(isset($prev[$target]) && $prev[$target]) {
$stack->push($target);
$distance += $graph[$target][$prev[$target]];
$target = $prev[$target];
}

if ($stack->isEmpty()) {
return ["distance" => 0, "path" => $stack];
} else {
$stack->push($source);
return ["distance" => $distance, "path" => $stack];
}
}
}

31 changes: 29 additions & 2 deletions tests/DataStructure/GraphTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function testTopologicalSort()

}

public function testFW()
public function testFloydWarshall()
{
$totalVertices = 5;
$graph = [];
Expand All @@ -107,9 +107,36 @@ public function testFW()
$graph[4][1] = $graph[1][4] = 10;
$graph[3][4] = $graph[4][3] = 20;

$distance = Graph::FW($graph);
$distance = Graph::floydWarshall($graph);

$this->assertEquals(20, $distance[0][4]);
$this->assertEquals(10, $distance[3][2]);
}

public function testDijkstra()
{
$graph = [
'A' => ['B' => 3, 'C' => 5, 'D' => 9],
'B' => ['A' => 3, 'C' => 3, 'D' => 4, 'E' => 7],
'C' => ['A' => 5, 'B' => 3, 'D' => 2, 'E' => 6, 'F' => 3],
'D' => ['A' => 9, 'B' => 4, 'C' => 2, 'E' => 2, 'F' => 2],
'E' => ['B' => 7, 'C' => 6, 'D' => 2, 'F' => 5],
'F' => ['C' => 3, 'D' => 2, 'E' => 5],
];

$source = "A";
$target = "F";

$result = Graph::Dijkstra($graph, $source, $target);
extract($result);

$this->assertEquals($distance, 8);

$way = [];
while (!$path->isEmpty()) {
$way[] = $path->pop();
}

$this->assertEquals(['A', 'C', 'F'], $way);
}
}

0 comments on commit e234924

Please sign in to comment.