php实现图的邻接表,关键路径,拓朴排序
<?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; } } ?>