AOV网络
用顶点表示活动的网络
用有向图表示先修和后修的关系。
在有向图中,用顶点表示活动,
用有向边< vi, vj >表示vi 必须先于 v j进行。
如果有有向环则说明某项活动以自己为先决条件,这是不对的。
图中明显没有环。
可以看到输出的顺序。
排序(这里不是按大小排)
例如: 课程应该先修哪一个门课。比如数据结构这门课的先修课是C++语言高等数学。
这样按照顺序排序然后输出,就可以知道怎么修读课程。
上图的修读顺序是F 、D、 C、A 、 B
步骤如下:
- 输入AOV网络,
- 在有向图中选一个入度为0 的点,删除并输出
- 从图中删去该顶点,以及相关联的边。
循环做
直到全部输出,
或者有环,终止。
这里用栈做辅助结构,用栈存所有入度为0 的结点。
template<class T, class E>
void Graph<T, E>::sort()
{
int i = 0 ,j=0, m=0;
Edge<T,E>* p = 0;
Stack<int> s;
for (i = 0; i < numVertices; i++)
{
if (count[i] == 0)
{
s.Push(i);
}
}
while (!s.Isempty())
{
s.Pop(i);
cout << " 顶点 : " << getVertexvalue(i) << endl;
m++;
p = NodeTable[i].adj;
while (p != 0)
{
count[p->dest]--;
if (count[p->dest] == 0) s.Push(p->dest);//退出循环时要输出该点
p = p->link;
}
}
if (m < numVertices)
{
cout << "图有回路 " << endl;
}
}
以下是算法结果:
完整图代码:
#include<iostream>
#include "Minheap.h"//自己建的
#include"Queue.h"//自己建的
#include"stack.h"//自己建的
using namespace std;
//图的邻接表结构(有向图)
const int DefaultVertices = 30;//默认最大顶点数
//边结点,下一个顶点的位置
template<class T, class E>//T为顶点名字
struct Edge {
int dest; //边的另一个顶点的位置
E cost; //边上的权值
Edge<T, E>* link; //这个点的下一条边
Edge() { dest = -1; cost = 0; link = NULL; }
Edge(int num, E weight) { dest = num; cost = weight; link = NULL; }
};
//顶点
template<class T, class E>//T为数据
struct Vertex {
T data; //顶点名字
Edge<T, E>* adj; //边链表的头指针
Vertex() {};
//friend istream& operator >>(istream& in, Vertex<T, E>& V);
friend ostream& operator <<(ostream& out, Vertex<T, E>& V);
};
template <class T, class E>
ostream& operator <<(ostream& out, Vertex<T, E>& V)
{
out << V.data<<endl;
}
//图
template<class T, class E> //T为顶点名字
class Graph
{
public:
int maxVertices; //图中最大顶点数
int numEdges; //当前边数
int numVertices; //当前顶点数
bool* visited; // 成员属性 辅助数组
Vertex<T, E>* NodeTable; //顶点表(各边链表的头指针)
Graph(int sz);
~Graph();
int* count;//记录每一个顶点的入度数 的 数组
int getVertexPos(T vetrex) {//给出顶点vetrex在图中的位置,可以改成散列的方式
for (int i = 0; i < numVertices; i++) {
if (NodeTable[i].data == Vertex)return i;
}
return -1;
}
T getVertexvalue(int x) {
return NodeTable[x].data;
}
void CreateNodeTable();
void dfs()
{
int i = 0, v0 = 0;
for (i = 0; i < numVertices; i++)
visited[i] = false;
cout << "输入深度优先遍历的出发点" << endl;
cin >> v0;
DFS(v0);
}
void DFS(int v);
void BFS();
void sort(); //拓扑排序
};
template<class T, class E>
Graph<T, E>::Graph(int sz) {//初始化
maxVertices = sz; numVertices = 0; numEdges = 0;
NodeTable = new Vertex<T, E>[maxVertices];//创建顶点表数组
visited = new bool[sz];
int i=0;
cout << " 请输入结点数 :" << endl;
cin >> numVertices;
count = new int[numVertices];
//初始化为0
for (i = 0; i < numVertices; i++)
{
count[i] = 0;
}
if (NodeTable == NULL || visited == NULL)
{
cerr << "存储分配错误!" << endl;
exit(0);
}
for (i = 0; i < maxVertices; i++) {
NodeTable[i].adj = NULL;//边链表头指针赋空
}
for (i = 0; i < numVertices; i++)
{
visited[i] = false;
}
CreateNodeTable();
}
template<class T, class E>
Graph<T, E>::~Graph() {
Edge<T, E>* p;
for (int i = 0; i < numVertices; i++)
{
p = NodeTable[i].adj; //保留头结点
while (p != 0)
{
NodeTable[i].adj = p->link;
delete p;
p = NodeTable[i].adj;
}
}
}
template<class T, class E>
void Graph<T, E>::CreateNodeTable()
{
int j = 0, i = 0, m = 0;
Edge<T, E>* p;
for (i = 0; i < numVertices; i++)
{
NodeTable[i].adj = 0;
cout << "输入结点 :" << endl;
cin >> NodeTable[i].data;
cout << "输入以它为起点的边数 : " << endl;
cin >> m; //建立的链表的长度
for (j = 0; j < m; j++)
{
p = new Edge<T, E>;
cout << "输入终点的 数组 下标号 : " << endl;
cin >> p->dest; //输入连接点的数组下标号
//入度数
count[p->dest]++;
//建链
p->link = NodeTable[i].adj;
NodeTable[i].adj = p;
}
}
}
//遍历递归,需要参数v的
//DFS=====类似前序遍历,就可以看成前序遍历(根左右)
template<class T, class E>
void Graph<T, E>::DFS(int v) //v表示起点
{
Edge<T, E>* p;
visited[v] = true;
cout << NodeTable[v].data << " -> ";
p = NodeTable[v].adj;
while (p != 0)
{
if (!visited[p->dest])
DFS(p->dest);//先把一个点的路走到头, 再找其他点作为起点
p = p->link;
}
}
//BFS====层次遍历(队列作为辅助结构)
//不需要初始值
template<class T, class E>
void Graph<T, E>::BFS()
{
for (int i = 0; i < numVertices; i++)
visited[i] = false;
int v = 0; //根结点的下标
Edge<T, E>* p;
SeqQueue<int> qu;//定义一个队列
cout << "输入一个出发点的位置:" << endl;
cin >> v;
qu.EnQueue(v);
visited[v] = true; //这里表示入列
while (!qu.IsEmpty())
{
v = qu.getFront(v); //取队头元素
qu.DeQueue(v); //弹出队头元素
if (!visited[v])
{
cout << NodeTable[v].data << " -> ";
visited[v] = true;
}
p = NodeTable[v].adj;
//找邻接点
while (p != 0)
{
if (!visited[p->dest])
qu.EnQueue(p->dest);
p = p->link;
}
}
}
template<class T, class E>
void Graph<T, E>::sort()
{
int i = 0 ,j=0, m=0;
Edge<T,E>* p = 0;
Stack<int> s;
for (i = 0; i < numVertices; i++)
{
if (count[i] == 0)
{
s.Push(i);
}
}
while (!s.Isempty())
{
s.Pop(i);
cout << " 顶点 : " << getVertexvalue(i) << endl;
m++;
p = NodeTable[i].adj;
while (p != 0)
{
count[p->dest]--;
if (count[p->dest] == 0) s.Push(p->dest);
p = p->link;
}
}
if (m < numVertices)
{
cout << "图有回路 " << endl;
}
}