拓扑排序:
- 前面说的是有环的图的应用,下面介绍有向无环图的应用,简称DAG图(Directed Acycline Graph),如下图所示。
有向无环图
- 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网(Activity On Vertex Network)。
- 设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,……,vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必须在vj之前,称这样的序列为拓扑序列。
- 所谓拓扑排序,其实就是对一个有向图构造拓扑序列的过程。如果此网的全部顶点都被输出,则说明它是不存在环的AOV网,如果输出顶点少了,说明这个网存在环,不是AOV网。
- 算法:从AOV网中选择一个入度为0的顶点输出,然后删除此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
代码示例
由于需要删除顶点,故采用邻接表结构较为方便,且在原来的顶点结构中添加一个入度域记录该顶点的入度。
ALGraph.h
#pragma once
#define MAXVEX 100
typedef char VertexType; //顶点类型
typedef int EdgeType; //边上的权值类型
struct EdgeNode //边表结点
{
int adjvex; //邻接点域,存储该节点对应的下标
EdgeType weight; //存储权值,非网图不需要
EdgeNode* next; //下一个邻接点
};
typedef struct VertexNode
{
int in; //添加一个入度域
VertexType data; //顶点
EdgeNode* firstEdge; //边表头指针
}AdjList[MAXVEX]; //顶点数组
struct GraphAdjList
{
AdjList adjList; //顶点数组
int numVertexes, numEdges; //实际图中顶点数和边数
};
//建立有向图的邻接表结构
void CreateALGraph(GraphAdjList& G);
//根据顶点名称查找其下标
int locateVertex(GraphAdjList G, VertexType v);
//拓扑排序
void TopologicalSort(GraphAdjList G);
ALGraph.cpp
#include "ALGraph.h"
#include <iostream>
#include <stack>
using namespace std;
//建立有向无环图的邻接表结构
void CreateALGraph(GraphAdjList& G)
{
cout << "请输入顶点个数和边个数:" << endl;
cin >> G.numVertexes >> G.numEdges;
cout << "请输入" << G.numVertexes << "个顶点:" << endl;
for (int i = 0; i < G.numVertexes; i++)
{
cin >> G.adjList[i].data;
G.adjList[i].in = 0;
G.adjList[i].firstEdge = NULL;
}
cout << "请输入" << G.numEdges << "条边:" << endl;
VertexType vertex1, vertex2;
int m, n;
int edge;
for (int i = 0; i < G.numEdges; i++)
{
cin >> vertex1 >> vertex2 >> edge; //输入边及其依附的两个顶点
m = locateVertex(G, vertex1); //弧的起点
n = locateVertex(G, vertex2); //弧的终点
if (m >= 0 && n >= 0)
{
//创建一个新的边结点
EdgeNode* e = new EdgeNode;
e->weight = edge;
e->adjvex = n;
e->next = G.adjList[m].firstEdge; //头插法插入顶点的firstedge
G.adjList[m].firstEdge = e;
G.adjList[n].in++; //更新入度
}
}
}
//根据顶点名称查找其下标
int locateVertex(GraphAdjList G, VertexType v)
{
for (int i = 0; i < G.numVertexes; i++)
{
if (v == G.adjList[i].data)
{
return i;
}
}
return -1;
}
//拓扑排序
void TopologicalSort(GraphAdjList G)
{
stack<int> s; //存放入度为0的顶点,只对该栈中的顶点进行操作
for (int i = 0; i < G.numVertexes; i++)
{
if (G.adjList[i].in == 0)
{
s.push(i);
}
}
int count = 0; //统计输出顶点个数
while (!s.empty()) //栈不为空则继续
{
int x = s.top();
cout << G.adjList[x].data << " "; //输出顶点
count++;
s.pop(); //出栈然后删除此顶点及对应的边
EdgeNode* e = G.adjList[x].firstEdge; //第一条边
while (e)
{
if (!(--G.adjList[e->adjvex].in)) //要删除的边对应的顶点入度减一,如果为0,则入栈
{
s.push(e->adjvex);
}
e = e->next;
}
}
if (count != G.numVertexes)
{
cout << "Sort Error" << endl;
}
else
{
cout << "Sort Success" << endl;
}
}
main.cpp
#include "ALGraph.h"
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
GraphAdjList ALG;
CreateALGraph(ALG); //创建有向无环图
TopologicalSort(ALG);
/*
B A 1
C B 1
D B 1
C D 1
*/
return 0;
}
网友评论