php实现迪杰斯特拉算法,并由小顶堆优化
1 php 2 3 class DEdge 4 { 5 public $nextIndex, $length; 6 7 public function __construct($nextIndex, $length) 8 { 9 $this->nextIndex = $nextIndex; 10 $this->length = $length; 11 } 12 } 13 14 class DNode 15 { 16 public $index, $distance, $edges = []; 17 18 public function __construct($index, $distance) 19 { 20 $this->index = $index; 21 $this->distance = $distance; 22 } 23 24 public function addEdge(DEdge $edge) 25 { 26 $this->edges[] = $edge; 27 } 28 } 29 30 class Dijkstra 31 { 32 protected $origin; 33 protected $graph = [], $dGraph = [], $heap = [], $visited = [], $heapVisited = []; 34 35 public function __construct(array $graph, $origin) 36 { 37 $this->graph = $graph; 38 $this->origin = $origin; 39 $this->visited[$origin] = true; 40 $this->initializeGraph(); 41 $this->initializeHeap(); 42 $this->calculateDistance(); 43 } 44 45 public function printDistance() 46 { 47 foreach ($this->dGraph as $dNodes) { 48 var_dump([$dNodes->index, $dNodes->distance]); 49 } 50 } 51 52 protected function initializeGraph() 53 { 54 foreach ($this->graph as $index => $edges) { 55 $dNode = new DNode($index, $edges[$this->origin]); 56 foreach ($edges as $toIndex => $edge) { 57 $dNode->addEdge(new DEdge($toIndex, $edge)); 58 } 59 $this->dGraph[$dNode->index] = $dNode; 60 } 61 } 62 63 protected function initializeHeap() 64 { 65 foreach ($this->dGraph as $index => $node) { 66 if ($index != $this->origin && $node->distance != INF) { 67 $this->addToHeap($node); 68 } 69 } 70 } 71 72 protected function calculateDistance() 73 { 74 while (($nearestNode = $this->heapPop()) != null) { 75 foreach ($nearestNode->edges as $edge) { 76 if ($this->dGraph[$edge->nextIndex]->distance > 77 $nearestNode->distance + $edge->length) { 78 $this->dGraph[$edge->nextIndex]->distance = 79 $nearestNode->distance + $edge->length; 80 if (!isset($this->heapVisited[$edge->nextIndex])) { 81 $this->addToHeap($this->dGraph[$edge->nextIndex]); 82 } else { 83 $this->keepHeap($this->heapVisited[$edge->nextIndex]); 84 } 85 } 86 } 87 } 88 } 89 90 protected function heapPop() 91 { 92 $heapCount = count($this->heap); 93 if ($heapCount > 0) { 94 $this->swap(0, $heapCount - 1); 95 } 96 $pop = array_pop($this->heap); 97 $this->keepHeap(0, false); 98 return $pop; 99 } 100 101 protected function keepHeap($startAt, $up = true) 102 { 103 if ($up) { 104 while ($startAt > 0) { 105 $parentIndex = intval(($startAt - 1) / 2); 106 if ($this->heap[$parentIndex]->distance > $this->heap[$startAt]->distance) { 107 $this->swap($parentIndex, $startAt); 108 $startAt = $parentIndex; 109 $this->heapVisited[$this->heap[$startAt]->index] = $startAt; 110 } else { 111 break; 112 } 113 } 114 } else { 115 $lastIndex = count($this->heap) - 1; 116 while ($startAt < $lastIndex) { 117 $lIndex = 2 * $startAt + 1; 118 $rIndex = $lIndex + 1; 119 if (isset($this->heap[$rIndex])) { 120 $minIndex = $this->heap[$lIndex]->distance < 121 $this->heap[$rIndex]->distance ? $lIndex : $rIndex; 122 } else if (isset($this->heap[$lIndex])) { 123 $minIndex = $lIndex; 124 } else { 125 break; 126 } 127 if ($this->heap[$startAt]->distance > $this->heap[$minIndex]->distance) { 128 $this->swap($minIndex, $startAt); 129 $startAt = $minIndex; 130 $this->heapVisited[$this->heap[$startAt]->index] = $startAt; 131 } else { 132 break; 133 } 134 } 135 } 136 } 137 138 protected function addToHeap(DNode $dNode) 139 { 140 $this->heap[] = $dNode; 141 $this->keepHeap(count($this->heap) - 1); 142 } 143 144 protected function swap($index1, $index2) 145 { 146 list($this->heap[$index1], $this->heap[$index2]) = 147 [$this->heap[$index2], $this->heap[$index1]]; 148 } 149 } 150 151 $graph = [ 152 [0, 4, INF, 2, INF], 153 [4, 0, 4, 1, INF], 154 [INF, 4, 0, 1, 3,], 155 [2, 1, 1, 0, 7], 156 [INF, INF, 3, 7, 0], 157 ]; 158 159 $start = 0; 160 161 $dijkstra = new Dijkstra($graph, $start); 162 163 $dijkstra->printDistance();