搞定PHP里的图数据结构有点儿难,但是咱们有个法宝——厉害的图算法!这个文章就要教你怎么用PHP玩转Dijkstra和Kruskal算法,这俩家伙可是图形问题的杀手锏。
Dijkstra算法的基本概念
Dijkstra算法简单说就是帮你找到最佳路线,不管有没有权重。它的这个过程就像是一棵不断长高的大树,每一步都会选择最矮的那根树枝来突破。最关键的地方就在于,它每次都选最短的路走,这样才能从起点连到终点。
搞定Dijkstra算法可离不开一个老伙计——优先队列。这个东西,在PHP里咱就用数组来代替。啥步骤?首先,把所有节点的距离设成宇宙最大值,差点儿忘了那源头,它得是零!然后不停地循环直到每个节点都干掉:找出队列里距离最短的那家伙,让它身边的小伙伴们知道新情况(更新它们的距离),接着让这些知情人入团(放入队列)。
Dijkstra算法的PHP实现
要搞定PHP中的Dijkstra算法,我们得掌握一些基础的图形知识,比如如何表示图以及如何用优先队列搞事情。你可能会觉得邻接矩阵或者邻接表这两个东东比较难理解,但是没关系,我们只需要敲几行代码就能把这个算法的原理弄明白了。看下面这个PHP的小例子就是这么简单的一回事儿~
php 搞定这个dijkstra(伊姆斯特)算法,只需要给你的矩阵$graph'和起点变量$source就行了! $dist = []; $visited = []; $nodes = count($graph); 从0开始数,数到所有节点,每次加1。 $dist[$i] = PHP_INT_MAX; $visited[$i] = false; } $dist[$source] = 0; 从零开始,每加上一次$count,就检查下$count是不是小于剩余的节点数。 对的,就是取最小距离。$u=$dist和$visited两个数值中的较小者! $visited[$u] = true; 只要$v还没到$nodes,就自加1去循环。 如果没碰到过$v,而且在$graph文件里也能找到$u和$v的相连关系,然后$dist[$u]还不是PHP最大值的话,最重要的是$dist[$u]+$graph[$u][$v]要比$dist[$v]小才行。 距离等于起点到终点的长度加上中间那个点的尺寸。 } } return $dist; } 在这里,我们来聊聊怎么求 ̶d²$。首先得知道你现在走过的路(即$ visited$)和已经去过的地方(即 $dist$)。然后?还需要一个小工具:优化过的公式。这个公式就是让我们把每一步都算出来,加起来就得到了最后的答案——距离最小值。 $min = PHP_INT_MAX; $minIndex = -1; 遍历一下每一个距离,并取名为$node和$distance。 如果没去过那个节点,而且距离小于等于某个值? $min = $distance; $minIndex = $node; return $minIndex;
Kruskal算法的基本概念
Kruskal算法就是用来找出有特定权值的图形里最小的生成树。这个最小的生成树包含了图形所有节点,而且每条边的重量加起来是最均匀的。Kruskal算法的步骤很简单,就是在图形里找出最小的线,然后保证不会出现圈再连起来,这样就可以逐渐地找到整个的最小生成树。
Kruskal算法就是挑边和找圈滴事儿。在咱们PHP里头,用那个叫”并查集”的东西就能快速帮你找出圈子了。这个并查集就是一个把各种元素分门别类的好工具,它能让你方便快捷地找到合适的对象,还能进行即时合并!
Kruskal算法的PHP实现
搞定Kruskal算法得懂点数据库的门道,特别是怎样用数组(或链表)创建交集(即所谓的“并查集”)。就是这么回事儿,一边敲敲代码,一边琢磨这个算法怎么运作就行了。
function kruskal($graph) {
class Graph { private $nodes = []; private $edges = []; public function addNode($node) { $this->nodes[] = $node; } public function addEdge($node1, $node2, $weight = 1) { $this->edges[$node1][$node2] = $weight; } public function dijkstra($source) { $distances = array_fill_keys($this->nodes, INF); $distances[$source] = 0; $visited = []; while (count($visited) nodes)) { $minDistance = INF; $minDistanceNode = null; foreach ($this->nodes as $node) { if (!in_array($node, $visited) && $distances[$node] edges[$minDistanceNode] as $neighbor => $weight) { $newDistance = $distances[$minDistanceNode] + $weight; if ($newDistance addNode('A'); $graph->addNode('B'); $graph->addNode('C'); $graph->addNode('D'); $graph->addEdge('A', 'B', 6); $graph->addEdge('A', 'C', 8); $graph->addEdge('A', 'D', 10); $graph->addEdge('B', 'C', 3); $graph->addEdge('B', 'D', 9); $graph->addEdge('C', 'D', 12); $distances = $graph->dijkstra('A'); var_dump($distances);
$result = [];
$i = 0;
$e = 0;
$graph = sortEdges($graph);
$parent = [];
$rank = [];
循环遍历每个节点,检查它们的边。
$parent[$node] = $node;
$rank[$node] = 0;
while $e < parent total minus one.
我们这样来分析,先取$graph[]数组中的第$i$个元素,然后用它依次给$u、$v、$w赋值。
$i++;
$x = find($parent, $u);
$y = find($parent, $v);
if ($x != $y) {
$e++;
$result[] = [$u, $v, $w];
就是把$parent和$rank加起来,再加上$x和$y。
return $result;
function find($parent, $i) {
if ($parent[$i] != $i) {
把$parent里的第$i个元素的位置,放到变量$parent里。
return $parent[$i];
咱们来做个union函数,参数有$parent(父节点)、$rank(层级编号)和$x,$y(坐标值)。
$xroot = find($parent, $x);
$yroot = find($parent, $y);
如果$rank[$xroot]$比$rank[$yroot]$小,那就这样。
$parent[$xroot] = $yroot;
class Graph { private $nodes = []; private $edges = []; public function addNode($node) { $this->nodes[] = $node; } public function addEdge($node1, $node2, $weight = 1) { $this->edges[] = [$node1, $node2, $weight]; } public function kruskal() { $parents = array_fill_keys($this->nodes, null); $ranks = array_fill_keys($this->nodes, 0); usort($this->edges, function($a, $b) { return $a[2] - $b[2]; }); $mst = []; foreach ($this->edges as $edge) { $x = $this->find($edge[0], $parents); $y = $this->find($edge[1], $parents); if ($x != $y) { $mst[] = $edge; $this->union($x, $y, $parents, $ranks); } } return $mst; } private function find($node, &$parents) { if ($parents[$node] === null) { return $node; } return $this->find($parents[$node], $parents); } private function union($x, $y, &$parents, &$ranks) { $xRoot = $this->find($x, $parents); $yRoot = $this->find($y, $parents); if ($xRoot == $yRoot) { return; } if ($ranks[$xRoot] > $ranks[$yRoot]) { $parents[$yRoot] = $xRoot; } else if ($ranks[$xRoot] addNode('A'); $graph->addNode('B'); $graph->addNode('C'); $graph->addNode('D'); $graph->addEdge('A', 'B', 6); $graph->addEdge('A', 'C', 8); $graph->addEdge('A', 'D', 10); $graph->addEdge('B', 'C', 3); $graph->addEdge('B', 'D', 9); $graph->addEdge('C', 'D', 12); $mst = $graph->kruskal(); var_dump($mst);
除了$Rank[$xroot]>=$Rank[$yroot]$之外,如果还满足下面这个条件,那就…
$parent[$yroot] = $xroot;
} else {
$rank[$xroot]++;
图算法的实际应用
说白了,图算法就是好用!特别在网络传输,社交网络啥的都能派上用场。比如你在解决图问题时,就有如Dijkstra和Kruskal这样的厉害助手。它们能帮你找出用户间最短路径或最小生成树。这个可对于了解网络动态,真是超乎想象的管用!
图算法的优化技巧
实际用起来,图算法有时候会卡住。想让它跑得快点儿,咱可以搞点小手段!比如,给这个Dijkstra算法弄点儿二叉堆或者斐波那契堆加速处理优先级排序。再说了,那个啥Kruskal算法也能用上路径压缩和按照顺序合并来搞定并查集的速度。
图算法的未来发展
现在的大数据和人工智能进步得很快,对图算法运用的前景越来越好!比如推荐系统、知识图谱和复杂网络分析这些地方,都能期待到图算法继续发挥大作用。所以只要科学家们不断努力,弄出更厉害的新算法,就肯定能搞定复杂的图数据结构了。
老铁们记住,PHP里的图算法能帮咱们轻松驾驭图数据结构!花时间学习并练熟Dijkstra和Kruskal计算法,遇到什么实际难题都不怕,还能让咱的应用更给力!下面我问大家一个问题哈:你们觉得将来图算法能干啥大事儿?会面临啥新挑战不?赶紧到留言区聊聊呗,也别忘了点个赞和转发这篇文章,让更多的小伙伴都能用上这个厉害的图算法呦~
评论0