在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,成为AOV网(Activity On Vertex Network)。所谓拓扑排序,就是对一个有向图构造拓扑序列的过程。
对AOV网进行拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
应用场景:各种各样的工程或项目的流程图中,满足各种应用场景的需要。
首先准备所需有向图的数据结构:
class EdgeNode
{
public $adjvex;
public $weight;
public $next;
public function __construct($adjvex, $next = null, $weight = 0)
{
$this->adjvex = $adjvex;
$this->next = $next;
$this->weight = $weight;
}
}
class VertexNode
{
public $in;
public $data;
public $firstedge = null;
public function __construct($in, $data, $firstedge)
{
$this->in = $in;
$this->data = $data;
$this->firstedge = $firstedge;
}
}
class Graph
{
public $adjList;
public $num;
public function __construct($adjList, $num)
{
$this->adjList = $adjList;
$this->num = $num;
}
}
然后准备数据:
$EdgeNode0 = new EdgeNode(11, new EdgeNode(5, new EdgeNode(4)));
$EdgeNode1 = new EdgeNode(8, new EdgeNode(4, new EdgeNode(2)));
$EdgeNode2 = new EdgeNode(9, new EdgeNode(6, new EdgeNode(5)));
$EdgeNode3 = new EdgeNode(13, new EdgeNode(2));
$EdgeNode4 = new EdgeNode(7);
$EdgeNode5 = new EdgeNode(12, new EdgeNode(8));
$EdgeNode6 = new EdgeNode(5);
$EdgeNode7 = null;
$EdgeNode8 = new EdgeNode(7);
$EdgeNode9 = new EdgeNode(11, new EdgeNode(10));
$EdgeNode10 = new EdgeNode(13);
$EdgeNode11 = null;
$EdgeNode12 = new EdgeNode(9);
$EdgeNode13 = null;
$adjList = array(
new VertexNode(0, 'V0', $EdgeNode0),
new VertexNode(0, 'V1', $EdgeNode1),
new VertexNode(2, 'V2', $EdgeNode2),
new VertexNode(0, 'V3', $EdgeNode3),
new VertexNode(2, 'V4', $EdgeNode4),
new VertexNode(3, 'V5', $EdgeNode5),
new VertexNode(1, 'V6', $EdgeNode6),
new VertexNode(2, 'V7', $EdgeNode7),
new VertexNode(2, 'V8', $EdgeNode8),
new VertexNode(2, 'V9', $EdgeNode9),
new VertexNode(1, 'V10', $EdgeNode10),
new VertexNode(2, 'V11', $EdgeNode11),
new VertexNode(1, 'V12', $EdgeNode12),
new VertexNode(2, 'V13', $EdgeNode13),
);
$graph = new Graph($adjList, 14);
然后,实现算法:
----------------------------- 第一种 --------------------------
$stackTop = -1;
$count = 0;
$stack = array();
foreach ($graph->adjList as $adjKey => $adjItem) {
if ($adjItem->in == 0) {
$stack[++$stackTop] = $adjKey;
}
}
while ($stackTop != -1) {
$getTop = $stack[$stackTop--];
printf("%s -> ", $graph->adjList[$getTop]->data);
$count += 1;
for ($e = $graph->adjList[$getTop]->firstedge; !empty($e); $e = $e->next) {
$k = $e->adjvex;
$graph->adjList[$k]->in -= 1;
if (!$graph->adjList[$k]->in) {
$stack[++$stackTop] = $k;
}
}
}
if ($count < $graph->num) {
exit('不是AOV网');
} else {
exit('是的');
}
------------------- 第二种 ---------------------------------
$stackTop = -1;
$count = 0;
$stack = array();
foreach ($graph->adjList as $adjKey => $adjItem) {
if ($adjItem->in == 0) {
$stackTop += 1;
$stack[$stackTop] = $adjKey;
}
}
while ($stackTop != -1) {
$stackTop -= 1;
$getTop = array_pop($stack);
printf("%s -> ", $graph->adjList[$getTop]->data);
$count += 1;
for ($e = $graph->adjList[$getTop]->firstedge; !empty($e); $e = $e->next) {
$k = $e->adjvex;
$graph->adjList[$k]->in -= 1;
if (!$graph->adjList[$k]->in) {
array_push($stack, $k);
$stackTop += 1;
}
}
}
if ($count < $graph->num) {
exit('不是AOV网');
} else {
exit('是的');
}
到这里,整个实现就基本结束了,算法实现第一种和第二种只有些微差别。
此文参考《大话数据结构》这本书,如果问题,请评论指正~