PHP实现图的邻接矩阵表示及几种简单遍历算法分析


Posted in PHP onNovember 24, 2017

本文实例讲述了PHP实现图的邻接矩阵表示及几种简单遍历算法。分享给大家供大家参考,具体如下:

在web开发中图这种数据结构的应用比树要少很多,但在一些业务中也常有出现,下面介绍几种图的寻径算法,并用PHP加以实现.

佛洛依德算法,主要是在顶点集内,按点与点相邻边的权重做遍历,如果两点不相连则权重无穷大,这样通过多次遍历可以得到点到点的最短路径,逻辑上最好理解,实现也较为简单,时间复杂度为O(n^3);

迪杰斯特拉算法,OSPF中实现最短路由所用到的经典算法,djisktra算法的本质是贪心算法,不断的遍历扩充顶点路径集合S,一旦发现更短的点到点路径就替换S中原有的最短路径,完成所有遍历后S便是所有顶点的最短路径集合了.迪杰斯特拉算法的时间复杂度为O(n^2);

克鲁斯卡尔算法,在图内构造最小生成树,达到图中所有顶点联通.从而得到最短路径.时间复杂度为O(N*logN);

<?php
/**
 * PHP 实现图邻接矩阵
 */
class MGraph{
  private $vexs; //顶点数组
  private $arc; //边邻接矩阵,即二维数组
  private $arcData; //边的数组信息
  private $direct; //图的类型(无向或有向)
  private $hasList; //尝试遍历时存储遍历过的结点
  private $queue; //广度优先遍历时存储孩子结点的队列,用数组模仿
  private $infinity = 65535;//代表无穷,即两点无连接,建带权值的图时用,本示例不带权值
  private $primVexs; //prim算法时保存顶点
  private $primArc; //prim算法时保存边
  private $krus;//kruscal算法时保存边的信息
  public function MGraph($vexs, $arc, $direct = 0){
    $this->vexs = $vexs;
    $this->arcData = $arc;
    $this->direct = $direct;
    $this->initalizeArc();
    $this->createArc();
  }
  private function initalizeArc(){
    foreach($this->vexs as $value){
      foreach($this->vexs as $cValue){
        $this->arc[$value][$cValue] = ($value == $cValue ? 0 : $this->infinity);
      }
    }
  }
  //创建图 $direct:0表示无向图,1表示有向图
  private function createArc(){
    foreach($this->arcData as $key=>$value){
      $strArr = str_split($key);
      $first = $strArr[0];
      $last = $strArr[1];
      $this->arc[$first][$last] = $value;
      if(!$this->direct){
        $this->arc[$last][$first] = $value;
      }
    }
  }
  //floyd算法
  public function floyd(){
    $path = array();//路径数组
    $distance = array();//距离数组
    foreach($this->arc as $key=>$value){
      foreach($value as $k=>$v){
        $path[$key][$k] = $k;
        $distance[$key][$k] = $v;
      }
    }
    for($j = 0; $j < count($this->vexs); $j ++){
      for($i = 0; $i < count($this->vexs); $i ++){
        for($k = 0; $k < count($this->vexs); $k ++){
          if($distance[$this->vexs[$i]][$this->vexs[$k]] > $distance[$this->vexs[$i]][$this->vexs[$j]] + $distance[$this->vexs[$j]][$this->vexs[$k]]){
            $path[$this->vexs[$i]][$this->vexs[$k]] = $path[$this->vexs[$i]][$this->vexs[$j]];
            $distance[$this->vexs[$i]][$this->vexs[$k]] = $distance[$this->vexs[$i]][$this->vexs[$j]] + $distance[$this->vexs[$j]][$this->vexs[$k]];
          }
        }
      }
    }
    return array($path, $distance);
  }
  //djikstra算法
  public function dijkstra(){
    $final = array();
    $pre = array();//要查找的结点的前一个结点数组
    $weight = array();//权值和数组
    foreach($this->arc[$this->vexs[0]] as $k=>$v){
      $final[$k] = 0;
      $pre[$k] = $this->vexs[0];
      $weight[$k] = $v;
    }
    $final[$this->vexs[0]] = 1;
    for($i = 0; $i < count($this->vexs); $i ++){
      $key = 0;
      $min = $this->infinity;
      for($j = 1; $j < count($this->vexs); $j ++){
        $temp = $this->vexs[$j];
        if($final[$temp] != 1 && $weight[$temp] < $min){
          $key = $temp;
          $min = $weight[$temp];
        }
      }
      $final[$key] = 1;
      for($j = 0; $j < count($this->vexs); $j ++){
        $temp = $this->vexs[$j];
        if($final[$temp] != 1 && ($min + $this->arc[$key][$temp]) < $weight[$temp]){
          $pre[$temp] = $key;
          $weight[$temp] = $min + $this->arc[$key][$temp];
        }
      }
    }
    return $pre;
  }
  //kruscal算法
  private function kruscal(){
    $this->krus = array();
    foreach($this->vexs as $value){
      $krus[$value] = 0;
    }
    foreach($this->arc as $key=>$value){
      $begin = $this->findRoot($key);
      foreach($value as $k=>$v){
        $end = $this->findRoot($k);
        if($begin != $end){
          $this->krus[$begin] = $end;
        }
      }
    }
  }
  //查找子树的尾结点
  private function findRoot($node){
    while($this->krus[$node] > 0){
      $node = $this->krus[$node];
    }
    return $node;
  }
  //prim算法,生成最小生成树
  public function prim(){
    $this->primVexs = array();
    $this->primArc = array($this->vexs[0]=>0);
    for($i = 1; $i < count($this->vexs); $i ++){
      $this->primArc[$this->vexs[$i]] = $this->arc[$this->vexs[0]][$this->vexs[$i]];
      $this->primVexs[$this->vexs[$i]] = $this->vexs[0];
    }
    for($i = 0; $i < count($this->vexs); $i ++){
      $min = $this->infinity;
      $key;
      foreach($this->vexs as $k=>$v){
        if($this->primArc[$v] != 0 && $this->primArc[$v] < $min){
          $key = $v;
          $min = $this->primArc[$v];
        }
      }
      $this->primArc[$key] = 0;
      foreach($this->arc[$key] as $k=>$v){
        if($this->primArc[$k] != 0 && $v < $this->primArc[$k]){
          $this->primArc[$k] = $v;
          $this->primVexs[$k] = $key;
        }
      }
    }
    return $this->primVexs;
  }
  //一般算法,生成最小生成树
  public function bst(){
    $this->primVexs = array($this->vexs[0]);
    $this->primArc = array();
    next($this->arc[key($this->arc)]);
    $key = NULL;
    $current = NULL;
    while(count($this->primVexs) < count($this->vexs)){
      foreach($this->primVexs as $value){
        foreach($this->arc[$value] as $k=>$v){
          if(!in_array($k, $this->primVexs) && $v != 0 && $v != $this->infinity){
            if($key == NULL || $v < current($current)){
              $key = $k;
              $current = array($value . $k=>$v);
            }
          }
        }
      }
      $this->primVexs[] = $key;
      $this->primArc[key($current)] = current($current);
      $key = NULL;
      $current = NULL;
    }
    return array('vexs'=>$this->primVexs, 'arc'=>$this->primArc);
  }
  //一般遍历
  public function reserve(){
    $this->hasList = array();
    foreach($this->arc as $key=>$value){
      if(!in_array($key, $this->hasList)){
        $this->hasList[] = $key;
      }
      foreach($value as $k=>$v){
        if($v == 1 && !in_array($k, $this->hasList)){
          $this->hasList[] = $k;
        }
      }
    }
    foreach($this->vexs as $v){
      if(!in_array($v, $this->hasList))
        $this->hasList[] = $v;
    }
    return implode($this->hasList);
  }
  //广度优先遍历
  public function bfs(){
    $this->hasList = array();
    $this->queue = array();
    foreach($this->arc as $key=>$value){
      if(!in_array($key, $this->hasList)){
        $this->hasList[] = $key;
        $this->queue[] = $value;
        while(!empty($this->queue)){
          $child = array_shift($this->queue);
          foreach($child as $k=>$v){
            if($v == 1 && !in_array($k, $this->hasList)){
              $this->hasList[] = $k;
              $this->queue[] = $this->arc[$k];
            }
          }
        }
      }
    }
    return implode($this->hasList);
  }
  //执行深度优先遍历
  public function excuteDfs($key){
    $this->hasList[] = $key;
    foreach($this->arc[$key] as $k=>$v){
      if($v == 1 && !in_array($k, $this->hasList))
        $this->excuteDfs($k);
    }
  }
  //深度优先遍历
  public function dfs(){
    $this->hasList = array();
    foreach($this->vexs as $key){
      if(!in_array($key, $this->hasList))
        $this->excuteDfs($key);
    }
    return implode($this->hasList);
  }
  //返回图的二维数组表示
  public function getArc(){
    return $this->arc;
  }
  //返回结点个数
  public function getVexCount(){
    return count($this->vexs);
  }
}
$a = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i');
$b = array('ab'=>'10', 'af'=>'11', 'bg'=>'16', 'fg'=>'17', 'bc'=>'18', 'bi'=>'12', 'ci'=>'8', 'cd'=>'22', 'di'=>'21', 'dg'=>'24', 'gh'=>'19', 'dh'=>'16', 'de'=>'20', 'eh'=>'7','fe'=>'26');//键为边,值权值
$test = new MGraph($a, $b);
print_r($test->bst());

运行结果:

Array
(
  [vexs] => Array
    (
      [0] => a
      [1] => b
      [2] => f
      [3] => i
      [4] => c
      [5] => g
      [6] => h
      [7] => e
      [8] => d
    )
  [arc] => Array
    (
      [ab] => 10
      [af] => 11
      [bi] => 12
      [ic] => 8
      [bg] => 16
      [gh] => 19
      [he] => 7
      [hd] => 16
    )
)

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php分页函数
Jul 08 PHP
用文本文件制作留言板提示(下)
Oct 09 PHP
PHP XML操作类DOMDocument
Dec 16 PHP
fleaphp crud操作之find函数的使用方法
Apr 23 PHP
基于PHP CURL用法的深入分析
Jun 09 PHP
Php-Redis安装测试笔记
Mar 05 PHP
PHP学习笔记(三):数据类型转换与常量介绍
Apr 17 PHP
php导出生成word的方法
Dec 25 PHP
PHP操作FTP类 (上传、下载、移动、创建等)
Mar 31 PHP
phpinfo()中Loaded Configuration File(none)的解决方法
Jan 16 PHP
三个思路解决laravel上传文件报错:413 Request Entity Too Large问题
Nov 13 PHP
PHP创建文件及写入数据(覆盖写入,追加写入)的方法详解
Feb 15 PHP
PHP+Apache环境中如何隐藏Apache版本
Nov 24 #PHP
实例分析基于PHP微信网页获取用户信息
Nov 24 #PHP
thinkPHP通用控制器实现方法示例
Nov 23 #PHP
PHP substr()函数参数解释及用法讲解
Nov 23 #PHP
Laravle eloquent 多对多模型关联实例详解
Nov 22 #PHP
PHP多维数组排序array详解
Nov 21 #PHP
Ecshop 后台添加新功能栏目及管理权限设置教程
Nov 21 #PHP
You might like
php+mysql实现数据库随机重排实例
2014/10/17 PHP
PHP微信开发用Cache 解决数据缓存
2016/07/11 PHP
PHP判断函数是否被定义的方法
2019/06/21 PHP
Laravel (Lumen) 解决JWT-Auth刷新token的问题
2019/10/24 PHP
通过JAVASCRIPT读取ASP设定的COOKIE
2006/11/24 Javascript
js动画(animate)简单引擎代码示例
2012/12/04 Javascript
onkeypress字符按键兼容所有浏览器使用介绍
2013/04/24 Javascript
jQuery父级以及同级元素查找介绍
2013/09/04 Javascript
Javascript实现返回上一页面并刷新的小例子
2013/12/11 Javascript
Document.location.href和.replace的区别示例介绍
2014/03/04 Javascript
JavaScript获取表单内所有元素值的方法
2015/04/02 Javascript
基于dropdown.js实现的两款美观大气的二级导航菜单
2015/09/02 Javascript
Angular实现form自动布局
2016/01/28 Javascript
JavaScript学习笔记之数组的增、删、改、查
2016/03/23 Javascript
jQuery Select下拉框操作小结(推荐)
2016/07/22 Javascript
jQuery实现动态控制页面元素的方法分析
2017/12/20 jQuery
JS中利用FileReader实现上传图片前本地预览功能
2018/03/02 Javascript
30分钟精通React今年最劲爆的新特性——React Hooks
2019/03/11 Javascript
微信小程序实现音乐播放页面布局
2020/12/11 Javascript
Vite和Vue CLI的优劣
2021/01/30 Vue.js
[59:53]DOTA2-DPC中国联赛 正赛 VG vs Elephant BO3 第二场 3月6日
2021/03/11 DOTA
Python遍历目录的4种方法实例介绍
2015/04/13 Python
python用户管理系统的实例讲解
2017/12/23 Python
Python标准库shutil用法实例详解
2018/08/13 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
Tensorflow 自定义loss的情况下初始化部分变量方式
2020/01/06 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
美国牛仔品牌:True Religion
2018/11/16 全球购物
Linux机考试题
2015/10/16 面试题
大学老师推荐信
2014/02/25 职场文书
公证书样本
2014/04/10 职场文书
杨善洲观后感
2015/06/04 职场文书
小王子读书笔记
2015/06/29 职场文书
《曾国藩家书》读后感——读家书,立家风
2019/08/21 职场文书
深入讲解Vue中父子组件通信与事件触发
2022/03/22 Vue.js
Python使用pandas导入xlsx格式的excel文件内容操作代码
2022/12/24 Python