数据结构:图--拓扑排序

拓扑排序

拓扑排序

在实际应用中,有向图的边可以看做是顶点之间制约关系的描述。把顶点看作是一个个任务,则对于有向边<Vi,Vj>表明任务Vj的完成需等到任务Vi完成之后,也就是说任务Vi先于任务Vj完成。对于一个有向图,找出一个顶点序列,且序列满足:若顶点Vi和Vj之间有一条边<Vi,Vj>,则在此序列中顶点Vi必在顶点Vj之前。这样的一个序列就称为有向图的拓扑序列(topological
order)。

步骤

  1. 从有向图中选取一个没有前驱(入度为0)的顶点输出。
  2. 删除图中所有以它为起点的弧。

重复上述两个步骤,此时会出现两种情形

1.所有顶点都已输出,输出序列就是拓扑序列。

2.已没有无前驱的顶点,但任然有顶点没有输出,这表明该有向图是有环的。

可见拓扑排序可以检测有向图是否有环。

必须指出,即使是存储结构已确定,拓扑序列也不一定是唯一的。拓扑排序序列不仅跟存储结构有关也与具体采用的算法有关。

代码

类定义

#include<iostream>
#include<iomanip>
#include<queue>
using namespace std;
/*
用邻接矩阵实现图
拓扑排序必须是有向图
*/
class Graph
{
private:
	//顶点数
	int numV;
	//边数
	int numE;
	//顶点的入度
	int *indegree;
	//邻接矩阵
	int **matrix;
public:
	/*
	构造方法
	numV是顶点数,isWeighted是否带权值,isDirected是否有方向
	*/
	Graph(int numV);
	//建图
	void createGraph(int numE);
	//析构方法
	~Graph();
	//获取顶点数
	int getVerNums()
	{
		return numV;
	}
	//获取边数
	int getEdgeNums()
	{
		return numE;
	}
	//拓扑排序
	void topologicalSort();
	//打印邻接矩阵
	void printAdjacentMatrix();
	//检查输入
	bool check(int, int);
};

类实现

//构造函数,指定顶点数目
Graph::Graph(int numV)
{
	//对输入的顶点数进行检测
	while (numV <= 0)
	{
		cout << "顶点数有误!重新输入 ";
		cin >> numV;
	}
	this->numV = numV;
	//构建邻接矩阵,并初始化
	matrix = new int*[numV];
	int i, j;
	for (i = 0; i < numV; i++)
		matrix[i] = new int[numV];
	//由于权值对于拓扑排序并无作用,故采取无权图的做法
	for (i = 0; i < numV; i++)
	for (j = 0; j < numV; j++)
		matrix[i][j] = 0;
	//构建顶点的入度数组,并初始化
	indegree = new int[numV];
	for (i = 0; i < numV; i++)
		indegree[i] = 0;
}
void Graph::createGraph(int numE)
{
	/*
	对输入的边数做检测
	一个numV个顶点的有向图,最多有numV*(numV - 1)条边
	*/
	while (numE < 0 || numE > numV*(numV - 1))
	{
		cout << "边数有问题!重新输入 ";
		cin >> numE;
	}
	this->numE = numE;
	int tail, head, i;
	i = 0;
	cout << "输入每条边的起点(弧尾)、终点(弧头)" << endl;
	while (i < numE)
	{
		cin >> tail >> head;
		while (!check(tail, head))
		{
			cout << "输入的边不正确!请重新输入 " << endl;
			cin >> tail >> head;
		}
		matrix[tail][head] = 1;
		indegree[head]++;
		i++;
	}
}
Graph::~Graph()
{
	int i;
	for (i = 0; i < numV; i++)
		delete[] matrix[i];
	delete[]matrix;
	delete[]indegree;
}
//拓扑排序
void Graph::topologicalSort()
{
	int i, vertex;
	queue<int> q;
	//入度为零的顶点入队
	for (i = 0; i < numV; i++)
	if (indegree[i] == 0)
		q.push(i);
	bool *visited = new bool[numV];
	for (i = 0; i < numV; i++)
		visited[i] = false;
	while (!q.empty())
	{
		vertex = q.front();
		q.pop();
		cout << setw(4) << vertex;
		visited[vertex] = true;
		for (i = 0; i < numV; i++)
		if (matrix[vertex][i] == 1)
		{
			//调整入度,入度为0则需入队
			if (!(--indegree[i]))
				q.push(i);
		}
	}
	cout << endl;
	for (i = 0; i < numV; i++)
	if (!visited[i])
		cout << "该有向图有环!";
	cout << endl;
	delete[]visited;
}
//打印邻接矩阵
void Graph::printAdjacentMatrix()
{
	int i, j;
	cout.setf(ios::left);
	cout << setw(4) << " ";
	for (i = 0; i < numV; i++)
		cout << setw(4) << i;
	cout << endl;
	for (i = 0; i < numV; i++)
	{
		cout << setw(4) << i;
		for (j = 0; j < numV; j++)
			cout << setw(4) << matrix[i][j];
		cout << endl;
	}
}
bool Graph::check(int tail, int head)
{
	if (tail < 0 || tail >= numV || head < 0 || head >= numV)
		return false;
	return true;
}

主函数

int main()
{
	cout << "******拓扑排序***by David***" << endl;
	int numV, numE;
	cout << "建图..." << endl;
	cout << "输入顶点数 ";
	cin >> numV;
	Graph graph(numV);
	cout << "输入边数 ";
	cin >> numE;
	graph.createGraph(numE);
	cout << "打印邻接矩阵..." << endl;
	graph.printAdjacentMatrix();
	cout << "拓扑排序..."<<endl;
	graph.topologicalSort();
	system("pause");
	return 0;
}

运行

完整代码下载:拓扑排序

转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38353517

若有所帮助,顶一个哦!

专栏目录:数据结构与算法目录

数据结构:图--拓扑排序,布布扣,bubuko.com

时间: 2024-12-29 11:17:11

数据结构:图--拓扑排序的相关文章

数据结构:拓扑排序之 确定比赛名词

[BestCoder Round #3 来了!]8月3号19:00~21:00(赛前30分钟停止注册比赛) 确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11642    Accepted Submission(s): 4634 Problem Description 有 N个比赛队(1<=N<=500),编号依次为1,

HDU4857——逃生(反向建图+拓扑排序)

逃生 Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前.同时,社会是不平等的,这些人有的穷有的富.1号最富,2号第二富,以此类推.有钱人就贿赂负责人,所以他们有一些好处.负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推.那么你就要安排大家的顺序.我们保证一

【数据结构】拓扑排序、最短路径算法、Dijkstra算法、无环图等等

图的定义 图(graph)G = (V,E)由顶点(vertex)的集V和边(Edge)的集E组成.有时也把边称作弧(arc),如果点对(v,w)是有序的,那么图就叫做有向的图(有向图).顶点v和w邻接(adjacent)当且仅当(v,w)属于E. 如果无向图中从每一个顶点到其他每个顶点都存在一条路径,则称该无向图是连通的(connected).具有这样性质的有向图称为是强连通的(strongly connected).如果有向图不是强连通的,但它的基础图(underlying graph)(也

【数据结构】拓扑排序算法

对AOV网进行拓扑排序的基本思路是: 从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止. AOV网及邻接表数据结构: 代码: #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h"

数据结构之拓扑排序

转自:http://blog.csdn.net/dm_vincent/article/details/7714519 原理:该算法的实现十分直观,关键在于需要维护一个入度为0(没有入)的顶点的集合: 每次从该集合中取出(没有特殊的取出规则,随机取出也行,使用队列/栈也行,下同)一个顶点,将该顶点放入保存结果的List中. 紧接着循环遍历由该顶点引出的所有边,从图中移除这条边,同时获取该边的另外一个顶点,如果该顶点的入度在减去本条边之后为0,那么也将这个顶点放到入度为0的集合中.然后继续从集合中取

算法系列之图--拓扑排序

本文介绍使用深度先搜索对向无环图(DAG)进行拓扑排序. 对于一个有向无环图G=(V,E)来说,其拓扑排序是G中所有结点的一种线性次序,该次序满足如下条件:如果G包含边(u,v)则结点u在拓扑排序中处于结点v的前面(若图G包含一个环路则不可能排出一个线性次序).可将图中的拓扑排序看成是将图的所有结点在一条水平线上排开,图中所有边都从左指向右. 给一个拓扑图如下示: 拓扑排序算法与DFS相似,但是在拓扑排序的过程中,每个结点都是后与其临接链表里的结点而放入Stack中. 具体代码如下示: 1 #i

CSU 1804: 有向无环图 拓扑排序 图论

1804: 有向无环图 Submit Page   Summary   Time Limit: 5 Sec     Memory Limit: 128 Mb     Submitted: 716     Solved: 298 Description Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始.点 v 结束的路径). 为了方便,点用 1,2,-,n 编号. 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0

图——拓扑排序(uva10305)

John has n tasks to do. Unfortunately, the tasks are not independent and the execution of one task is only possible if other tasks have already been executed. Input The input will consist of several instances of the problem. Each instance begins with

BZOJ 1565 NOI2009 植物大战僵尸 最大权闭合图+拓扑排序

题目大意:给定一个m*n的草坪,每块草坪上的植物有两个属性: 1.啃掉这个植物,获得收益x(可正可负) 2.保护(r,c)点的植物不被啃掉 任何一个点的植物存活时,它左侧的所有植物都无法被攻击 求最大收益 首先这个保护和被保护的关系就是最大权闭合图的连边关系 然后直接跑就行 然后我们就会发现没过样例0.0 原因当图出现环时,根据题意,环上的所有点都不能取(想象一个无冷却的食人花前面放一个坚果) 所以这题还要去掉环 由于环上的点不能取,所以所有指向环上的点的点都不能取 这个条件看起来不太好做,我们