设为首页 收藏本站
查看: 737|回复: 0

[经验分享] php实现图的邻接表,关键路径,拓朴排序

[复制链接]

尚未签到

发表于 2017-4-9 08:28:32 | 显示全部楼层 |阅读模式
<?php
//调用
require 'alGraph.php';
$a = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j');
$e = array('ab'=>'3', 'ac'=>'4', 'be'=>'6', 'bd'=>'5', 'cd'=>'8', 'cf'=>'7', 'de'=>'3', 'eg'=>'9', 'eh'=>'4', 'fh'=>'6', 'gj'=>'2', 'hi'=>'5', 'ij'=>'3');
$test = new ALGraph($a, $e, 1, 1);
print_r($test->criticalPath());
?>


alGraph.php
<?php
/**
* PHP实现图的邻接表
*
* @author zhaojiangwei
* @since  2011/11/1 16:00
*/
//顶点类   
class Vex{
private $data;
private $headLink;//第一条边
private $enterLimit = 0;//顶点的入度
public function Vex($data, $headLink = NULL){
$this->data = $data;
$this->headLink = $headLink;
}
//入度加+n
public function enterLimitAdd($n = 1){
$this->enterLimit += $n;
}
public function getEnterLimit(){
return $this->enterLimit;
}
public function getData(){
return $this->data;
}
public function getHeadLink(){
return $this->headLink;
}
public function setHeadLink(& $link){
$this->headLink = $link;
}
}
//边类
class Arc{
private $key;//该边顶点对应在顶点数组的下标
private $weight;//路径长度
private $next;//下一条边
public function Arc($key, $weight = NULL, $next = NULL){
$this->key= $key;
$this->next = $next;
$this->weight= $weight;
}
public function getWeight(){
return $this->weight;
}
public function getKey(){
return $this->key;
}
public function getNext(){
return $this->next;
}
public function setNext($next){
$this->next = $next;
}
}
//邻接表类
class ALGraph{
private $vexsData;//外部输入的顶点数据,类似如array('a', 'b');
private $vexs;//顶点数组
private $arcData;//外部输入的边数据,如array('ab'=>'3'),键为边,值为权值
private $excuteDfsResult;//深度优先遍历后的字符串结果
private $hasList; //遍历时储存遍历过的结点下标
private $queue; //广度优先遍历时的存储队列
private $direct; //是否是有向图,0为无向,1为有向
private $weight; //是否带权,0不带,1带
//$direct:是否是有向图,0无向,1有向
//$weight:是否带权,0不带,1带
public function ALGraph($vexsData, $arcData, $direct = 0, $weight = 0){
$this->vexsData = $vexsData;
$this->arcData = $arcData;
$this->direct = $direct;
$this->weight = $weight;
$this->createHeadList();
$this->createArc();
}
//创建顶点数组
private function createHeadList(){
foreach($this->vexsData as $value){
$this->vexs[] = new Vex($value);
}
}
//创建边表
private function createArc(){
switch($this->weight){
case '0'://不带权
$this->createNoWeightArc();
break;
case '1'://带权
$this->createWeightArc();
break;
}
}
//创建带权表
private function createWeightArc(){
foreach($this->arcData as $key=>$value){
$edgeNode = str_split($key);
$this->createConnect($edgeNode[0], $edgeNode[1], $value);
if(!$this->direct){//有向图
$this->createConnect($edgeNode[1], $edgeNode[0], $value);
}
}
}
//创建不带权表
private function createNoWeightArc(){
foreach($this->arcData as $value){
$str = str_split($value);
$this->createConnect($str[0], $str[1]);
if(!$this->direct){
$this->createConnect($str[1], $str[0]);
}
}
}
//依附于边的俩顶点建立关系
//$weight: 权值,默认为无权值
private function createConnect($first, $last, $weight = NULL){
$lastTemp=& $this->vexs[$this->getVexByValue($last)];
$lastTemp->enterLimitAdd(1);//入度+1
$firstNode =& $this->vexs[$this->getVexByValue($first)];
$lastNode = new Arc($this->getVexByValue($last), $weight);
$lastNode->setNext($firstNode->getHeadLink());
$firstNode->setHeadLink(& $lastNode);
}
//关键路径算法
public function criticalPath(){
$etvs = array();//最早开始时间
$ltvs = array();//最晚开始时间
$stacks = array();//拓朴排序结点栈
$result = array();//返回的结果
foreach($this->vexs as $value){
$etvs[$value->getData()] = 0;   
}
$this->expandSeq($etvs, $stacks);//拓朴排序,并填充$etvs与$stacks
$temp = end($etvs);//结点栈的栈顶点,为数组的最后一个元素
foreach($this->vexs as $value){
$ltvs[$value->getData()] = $temp;                    
}
while($top = array_pop($stacks)){
$pre = $top->getHeadLink();
while($pre){
$tempNode = $this->vexs[$pre->getKey()];
if($ltvs[$top->getData()] > $ltvs[$tempNode->getData()] - $pre->getWeight()){
$ltvs[$top->getData()] = $ltvs[$tempNode->getData()] - $pre->getWeight();
}
$pre = $pre->getNext();
}
}
foreach($this->vexs as $value){
if($ltvs[$value->getData()] == $etvs[$value->getData()]){
$result[] = $value->getData();
}
}
return $result;
}
//拓扑排序
//$etv,关键路径,找最早开始时间,默认为不找
//$stack排序后的顶点栈
public function expandSeq(& $etv = FALSE, & $stacks){
$zeroEnter = array();
$result = array();
foreach($this->vexs as $value){
if($value->getEnterLimit() == 0){
$zeroEnter[] = $value;   
}
}
while(!empty($zeroEnter)){
$node = array_shift($zeroEnter);
$result[] = $node->getData();
array_push($stacks, $node);
$pre = $node->getHeadLink();
while($pre){
$temp =& $this->vexs[$pre->getKey()];
$temp->enterLimitAdd(-1);
if($etv){
if($etv[$temp->getData()] < $etv[$node->getData()] + $pre->getWeight()){
$etv[$temp->getData()] = $etv[$node->getData()] + $pre->getWeight();
}
}
if($temp->getEnterLimit() == 0){
$zeroEnter[] = $temp;
}
$pre = $pre->getNext();
}
}
return $result;
}
//根据顶点的值返回顶点在顶点数组中的下标
private function getVexByValue($value){
foreach($this->vexs as $k=>$v){
if($v->getData() == $value){
return $k;
}
}
}
//广度优先遍历
public function bfs(){
$this->hasList = array();
$this->queue = array();
foreach($this->vexs as $key=>$value){
if(!in_array($value->getData(), $this->hasList)){
$this->hasList[] = $value->getData();
$this->queue[] = $value->getHeadLink();
while(!empty($this->queue)){
$node = array_shift($this->queue);
while($node){
if(!in_array($this->vexs[$node->getKey()]->getData(), $this->hasList)){
$info = $this->vexs[$node->getKey()];
$this->hasList[] = $info->getData();
$this->queue[] = $info->getHeadLink();
}
$node = $node->getNext();
}
}
}
}
return implode($this->hasList);
}
//深度优先遍历入口
public function dfs(){
$this->hasList = array();
foreach($this->vexs as $key=>$value){
if(!in_array($key, $this->hasList)){
$this->hasList[] = $key;
$this->excuteDfs($this->vexs[$key]->getHeadLink());
}
}
foreach($this->hasList as $key=>$value){
$this->hasList[$key] = $this->vexs[$value]->getData();   
}
return implode($this->hasList);
}
//执行深度遍历
private function excuteDfs($arc){
if(!$arc || in_array($arc->getKey(), $this->hasList)){
return false;   
}
$this->hasList[] = $arc->getKey();
$next = $this->vexs[$arc->getKey()]->getHeadLink();
while($next){  
$this->excuteDfs($next);
$next = $next->getNext();
}
}
public function getVexs(){
return $this->vexs;
}
}
?>

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-362217-1-1.html 上篇帖子: php的IDE(集成开发环境)选用指南[1] 下篇帖子: iPhone 搭建PHP版Push服务器 实例操作
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表