(1小时数据结构)数据结构c++描述(二十七)--- 图(拓扑排序)

AOV图定义:

     在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网。(Activity On Vertex)

如下图:

(1小时数据结构)数据结构c++描述(二十七)--- 图(拓扑排序)_第1张图片

必须有个先后的顺序,C0 在 C2的前面。

拓扑排序: 

     设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,...,vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在vj之前,则我们称这样的顶点序列为一个拓扑序列。

由定义我们采用了两种方式来解决这个问题。入度法,与DFS逆序法。

首先要表明,你的图必须是有向无环的,不然就不符合AOV网了。

 1.入度法:

  如上图,我们可以知道 C0,与C1可以为入度的条件,找到C0,去掉C0节点与边,这个时候入度的是 C1 与 C7,以此类推

就可以解决此问题了,那如何确定要入的度呢,定义一个数组:inDegree[n], 初始化为0,然后遍历,出现节点的位置有加一,

比如:inDegree[i]++; i是遍历到的位置。这样遍历的话,只有发现0  1是入度,然后将 0 1放入一个队列中报存,然后取出队列

当0取出后,它指向的节点7,因为遍历了1次,他的inDegree[7] = 1;然后减去1,这个时候变成 0,就是新的度了。以此下去就是

我们的入度的办法了。

//拓扑排序
template
 void Graph::TopoSort()
{
	 if (HasCycle()) 
	 {       //存在环,直接返回
		 cout << "Cycle exists." << endl;
		 return;
	 }

	 int *inDegree = new int[n];
	 for (int i = 0; i < n; ++i) 
	 {
		 inDegree[i] = 0;
	 }

	 CalInDegree(inDegree);
	 queue topoQueue;
	 //将入度为0的顶点存入队列
	 for (int j = 0; j < n; ++j) 
	 {
		 if (inDegree[j] == 0) 
		 {
			 topoQueue.push(j);
		 }
	 }

	 int v;
	 int k;
	 while (!topoQueue.empty())
	 {
		 v = topoQueue.front();
		 topoQueue.pop();

		 cout << v << " ";
		 for (ENode *w = enodes[v]; w; w = w->next) 
		 {
			 k = w->adjVex;
			 inDegree[k]--;  //所有由顶点v指出的邻接点入度-1
			 if (0 == inDegree[k])
			 {     //更新后入度为0,则存进队列
				 topoQueue.push(k);
			 }
		 }
	 }
}



//计算所有顶点的入度
template
void Graph::CalInDegree(int * inDegree)
{
	for (int i = 0; i < n; ++i)
	{
		for (ENode *w = enodes[i]; w; w = w->next)
		{
			inDegree[w->adjVex]++;
		}
	}
}

有关HasCycle()是我上一章节的内容,想要了解的话,可以找到我上章节的内容:

图中是否又环

2.DFS逆序法

有DFS遍历可以知道,遍历出来的,逆序就是这个图形成的原因,举个例子:

(1小时数据结构)数据结构c++描述(二十七)--- 图(拓扑排序)_第2张图片

b是a 通过DFS所变成的样子,逆序栈就是8 5 2 3 6 9 7 4 1, 对应的是 1 4 7 9 6 3 2 5 8,可以看出来是不是形成图的过程。

代码:

//用DFS来求拓扑序列
 //一幅有向无环图的拓扑顺序即为DFS中所有顶点的逆后序排列,所以只要求该逆后序排列就好
 //如果该图是有环的,就说明拓扑序列不存在,尽管该逆后序排列仍能求出来
template
void Graph::TopoSortByDFS()
{
	if (HasCycle()) 
	{       //存在环,直接返回
		cout << "Cycle exists." << endl;
		return;
	}
	CalReversePost();
}

//通过调用DFSForReversePost来求得
template
void Graph::CalReversePost()
{
	ClearReversePost();
	bool *visited = new bool[n];
	for (int i = 0; i < n; ++i) {
		visited[i] = false;
	}
	for (int j = 0; j < n; ++j) {
		if (!visited[j]) {
			DFSForReversePost(j, visited);
		}
	}
	delete[] visited;
}

//清空栈reversePost中的记录
template
void Graph::ClearReversePost()
{
	while (!reversePost.empty())
	{
		reversePost.pop();
	}
}

template
 void Graph::DFSForReversePost(int v, bool * visited)
{
	 visited[v] = true;
	 for (ENode *w = enodes[v]; w; w = w->next) {
		 if (!visited[w->adjVex]) {
			 DFSForReversePost(w->adjVex, visited);
		 }
	 }
	 reversePost.push(v);    //这是和普通的DFS唯一不同的地方!
}

//返回DFS中顶点的逆后序序列
template
 stack Graph::GetReversePost()
{
	 //因为栈的特殊性,这里直接返回一个拷贝,以保证源栈不会因为外界操作而改变
	 stack tmp(reversePost);
	 return tmp;
}

代码测试:

void testGraph()
{
	const int n = 9;
	Graph graph(n);
	set edgeinput[n];
	edgeinput[0].insert({ 2,7 });
	edgeinput[1].insert({ 2,3,4 });
	edgeinput[2].insert({ 3 });
	edgeinput[3].insert({ 5, 6 });
	edgeinput[4].insert({ 5 });
	edgeinput[7].insert({ 8 });
	edgeinput[8].insert({ 6 });

	for (int i = 0; i< n; i++)
	{
		for (auto iter = edgeinput[i].begin(); iter != edgeinput[i].end(); iter++)
		{
			graph.Insert(i, *iter, 1);  // 1是权重
		}
	}

	//测试深度优先遍历
	cout << "DFS:";
	graph.DFS();
	cout << endl;

	//测试宽度优先遍历
	cout << "BFS:";
	graph.BFS();
	cout << endl;

	//测试是否有环
	if (graph.HasCycle()) {
		cout << "cycle:";
		stack cycle = graph.GetCycle();
		while (!cycle.empty()) {
			cout << cycle.top() << " ";
			cycle.pop();
		}
		cout << endl;
	}
	else {
		cout << "cycle doesn't exist." << endl;
	}

	//测试拓扑排序
	cout << "TopoSort:";
	graph.TopoSort();
	cout << endl;

	//测试用DFS来求拓扑序列
	cout << "TopoSort By ReversePost:";
	graph.TopoSortByDFS();
	stack topo = graph.GetReversePost();
	while (!topo.empty()) {
		cout << topo.top() << " ";
		topo.pop();
	}
	cout << endl;
}

 测试结果:

 

(1小时数据结构)数据结构c++描述(二十七)--- 图(拓扑排序)_第3张图片

(1小时数据结构)数据结构c++描述(二十七)--- 图(拓扑排序)_第4张图片

在我的数据结构与算法一栏中,有个目录文章,包含每个数据结构的目录,另外还有源码代码,需要的话可以关注我博客,后面会有图的其他相关代码。

你可能感兴趣的:(数据结构与算法)