AOV网络(有向图)----拓扑排序--判断有无环的问题--12月18日

AOV网络

用顶点表示活动的网络
用有向图表示先修和后修的关系。

在有向图中,用顶点表示活动,
用有向边< vi, vj >表示vi 必须先于 v j进行。

如果有有向环则说明某项活动以自己为先决条件,这是不对的。

在这里插入图片描述
图中明显没有环。
可以看到输出的顺序。

排序(这里不是按大小排)

例如: 课程应该先修哪一个门课。比如数据结构这门课的先修课是C++语言高等数学。

这样按照顺序排序然后输出,就可以知道怎么修读课程。

上图的修读顺序是F 、D、 C、A 、 B

步骤如下:

  1. 输入AOV网络,
  2. 在有向图中选一个入度为0 的点,删除并输出
  3. 从图中删去该顶点,以及相关联的边。
    循环做

直到全部输出,
或者有环,终止。

这里用栈做辅助结构,用栈存所有入度为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;
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值