<?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;
}
}
?>