用邻接表表示AOV网,并判断是否是有向无环图

1. 注:本代码中的思想来源于s1mba。膜拜大神!

2. 本代码在邻接矩阵的基础上创建邻接表。这样做的方便性就是,在邻接矩阵中我们可以很直观的表示出两个顶点是否相连,而且通过是不是对称矩阵的方式区分是不是有向图。这一点在创建邻接表时很重要,用 if (G.arcs[ i ][ j ] == 1)判断是不是要创建新的表结点。

3. 另外,在邻接表的顶点表中外加一个入度域in也是点睛之笔,这是为了方便判断结点入度是否为0,从而决定是否入栈。

4. By the way,本代码中用的是STL库中的stack容器,更加方便。用数组还要用下标index移来移去,边界条件什么的感觉很麻烦。虽然数组可能速度更快

5. TopologicalSort的思想映射在邻接表数据结构上的表现要好好思考。先遍历一遍邻接表,把入度已经为0的结点内容先入栈,然后从栈中开始一个一个的选,用while (!ZeroDegreeNodeStack.empty())来做循环条件,从栈中的结点那一行链表开始遍历,后面链表中每个结点的入度都 -- ,然后判断 -- 后是否为0,如果为0就入栈。

6. 在上面遍历的时候要注意一点就是,输出了栈顶的结点内容之后,确实要出栈,然后记录出栈结点数cnt++,但是要用一个辅助变量cur来保存栈顶元素的值用于for循环中的初始条件。

7. 千万不要把stack.pop()操作放在for循环的后面,因为这样就会导致在for循环中入栈的元素直接就出栈了,还没输出呢就出栈了,从逻辑上就是错误的!

上代码:

#include <iostream>
#include <stack>

using namespace std;
/**
* 1.用邻接矩阵创建图 但是由于在拓扑排序中需要进行删除顶点操作, 所以用邻接表会更加方便
* 因此我们创建好图的邻接矩阵后,再用邻接矩阵创建邻接表
* 2.由于需要经常判断结点的入度是否为0,所以我们在邻接表的顶点表中加入一个存放入度的数据域in
*/
#define MaxVertexNum 100
#define Infinity 10000

//邻接矩阵结构定义
typedef	struct { 
	int vers[MaxVertexNum]; //顶点数组
	int arcs[MaxVertexNum][MaxVertexNum]; //边数组
	int vernum, arcnum; //点和边的数目
}AMGraph;

//邻接表的表结点结构定义
typedef struct EdgeNode {
	int adjver; //存储该邻接点在顶点表中的下标
	struct EdgeNode* next; //指向下一个邻接点的指针域
}EdgeNode;

//邻接表的顶点表结构定义
typedef struct {
	int in; //入度域
	int data; //存放结点的内容,在本实验AOV网中存放的是int值
	EdgeNode* firstEdge; //指向第一个邻接结点的指针域
}VertexNode, AdjVerList[MaxVertexNum];

//邻接表的结构体定义
typedef struct {
	AdjVerList adjverList;
	int vernum, arcnum; //顶点数和边数
}adjlist, *AdjList; //前面一个不带指针的是为了分配空间

void CreatAM(AMGraph &G) { //初始化邻接矩阵
	cout << "请输入该图的顶点数和边数:" << endl;
	cin >> G.vernum >> G.arcnum;
	for (int i = 1; i <= G.vernum; i++) {
		G.vers[i] = i;
	}
	for (int i = 1; i <= G.vernum; i++) {
		for (int j = 1; j <= G.vernum; j++) {
			G.arcs[i][j] = 0;
		}
	}
	G.arcs[1][2] = 1;
	G.arcs[1][3] = 1;
	G.arcs[2][4] = 1;
	G.arcs[3][4] = 1;
	G.arcs[4][5] = 1;
}

void CreatAdjList(AMGraph G, AdjList &AL) { //创建邻接表
	EdgeNode* p;
	AL = new adjlist;
	AL->vernum = G.vernum;
	AL->arcnum = G.arcnum;
	for (int i = 1; i <= G.vernum; i++) { //初始化
		AL->adjverList[i].data = G.vers[i]; //结点信息复制
		AL->adjverList[i].in = 0;
		AL->adjverList[i].firstEdge = NULL;
	}
	for (int i = 1; i <= G.vernum; i++) {
		for (int j = 1; j <= G.vernum; j++) {
			if (G.arcs[i][j] == 1){ //如果有边
				p = new EdgeNode;
				p->adjver = j; //该邻接点在顶点表中的下标
				p->next = AL->adjverList[i].firstEdge; //头插法
				AL->adjverList[i].firstEdge = p;
				AL->adjverList[j].in++; //注意这里是j!
			}
		}
	}
}

void TopologicalSort(AdjList AL) {
	EdgeNode* p;
	int cnt = 0; //统计已经删除过的结点个数 用于判断是不是个有向无环图
	stack<int> ZeroDegreeNodeStack; //存放入度为0的栈
	for (int i = 1; i <= AL->vernum; i++) {
		if (AL->adjverList[i].in == 0) {
			ZeroDegreeNodeStack.push(i); //把结点的内容入栈
		}
	}
	while (!ZeroDegreeNodeStack.empty()) {
		cout << ZeroDegreeNodeStack.top() << "->"; //输出结点内容
		int cur = ZeroDegreeNodeStack.top(); //辅助变量
		ZeroDegreeNodeStack.pop(); 
		cnt++;
		for (p = AL->adjverList[cur].firstEdge; p != NULL; p = p->next) {
			AL->adjverList[p->adjver].in--;
			if (AL->adjverList[p->adjver].in == 0) { //如果删除掉这个节点,入度减1后变为0,那就入栈
				ZeroDegreeNodeStack.push(p->adjver);
			}
		}//for
	}//while
	cout << endl;
	if (cnt == AL->vernum)
		cout << "该AOV网是一个有向无环图!" << endl;
	else
		cout << "该AOV网不是一个有向无环图" << endl;
}

int main() {
	AMGraph G; //邻接矩阵
	AdjList AL; //邻接表

	CreatAM(G); //创建邻接矩阵
	CreatAdjList(G, AL); //在邻接矩阵的基础上创建邻接表

	cout << "拓扑排序的结果为:" << endl;
	TopologicalSort(AL);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值