拓扑排序

Posted gavanwanggw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拓扑排序相关的知识,希望对你有一定的参考价值。

1、什么是拓扑排序

对于有向无环图G=(V,E),G的拓扑排序是G中全部节点的一种线性次序。该次序满足例如以下条件:对于图中的一

有向边<u。v>,在拓扑排序中u节点位于v节点的前面(假设图G包括回路,则不可能排出一个线性次序)。能够将图的拓扑排序看做是将图的全部节点排在一条水平线上,有向图中的全部有向边都从左指向右。

2、拓扑排序解决的实际问题

我在这里介绍使用拓扑排序解决现实生活中的一个起床穿衣的问题。

在起床的过程中,我们必须先穿某些衣服,

后再去穿另外一些衣服。有些衣服则能够以随意顺序穿上,在下图中有向边<u,v>表明服装u必须在服装v之前穿上。

我们该怎样解决穿衣问题呢?

技术分享
3、拓扑排序算法
我们须要两个队列集合A、B,当中集合A用来存放入度为0的节点,集合B用来存放排好序的节点。拓扑排序算
法的步骤为:①初始化集合A、B为空;②将入度为0的节点增加集合A。③从集合A中取元素,将取出的元素增加集合B,并将此元素所指向的全部节点的入度减1。假设有节点的入度减为0,则将其增加到集合A中。④反复步骤③直到结合A为空为止,此时集合B中即为拓扑排序结果。
#include <iostream>
/*拓扑排序:
给定一个有向无环图,把图G中的全部顶点排成一个线性序列,
使得图中随意边<u,v>。在线性序列中顶点u在顶点v的前面。
基本思想:
①从图中选取入度为0的顶点。并将这些顶点增加队列集合A中;
②依次从队列集合A中取元素,将该元素增加到队列集合B中,同一时候将该元素所连接的顶点的入度减1。
假设顶点的入度减为0,则将该顶点增加到集合A中。
③反复②,直到集合A为空。
*/
typedef char ElemType;
const int WHITE = 0;
const int BLACK = 1;
const int MAX_VERTEX = 30;
const int MAX_ARC = 900;
/*边的数据结构*/
typedef struct arc_node
{
	int position;//存储边的还有一个顶点下标
	int weight;//边的权重
	struct arc_node *next;//指向下一条边
}ANode, *pArc;
/*顶点的数据结构*/
typedef struct vertex_node
{
	ElemType data;
	pArc first_arc;//指向第一条弧
}VNode, *pVNode;
/*图的数据结构*/
typedef struct graphic_node
{
	int vertex_num;//顶点数量
	int arc_num;//边的数量
	pVNode vertex[MAX_VERTEX];//用来存放顶点的数组
}Graphic, *pGNode;

/*辅助数据结构:队列*/
typedef struct queue_node
{
	int data;
	struct queue_node *next;
}QNode,*pQNode;
typedef struct queue
{
	pQNode front;
	pQNode tail;
}Queue;
void topologic_sort(Graphic g);
void create_graphic(pGNode g, int direction);
/*要想改动内容必须传指针,要想改动内容指向的值能够不传指针*/
void init_queue(Queue *q);
bool isempty_queue(Queue q);
void insert_queue(Queue *q, int e);
bool delete_queue(Queue *q, int *e);//当删除最后一个元素的时候一定要改动尾部指针
using namespace std;
int main()
{
	Graphic g;
	create_graphic(&g,1);
	topologic_sort(g);
	return 0;
}

void create_graphic(pGNode g, int direction)//direction = 0表示创建的是无向图。非0值是有向图
{
	cout << "输入顶点数" << endl;
	cin >> g->vertex_num;
	cout << "输入边数" << endl;
	cin >> g->arc_num;

	int i;
	cout << "输入" << g->vertex_num << "个顶点" << endl;
	for (i = 0; i < g->vertex_num; i++)
	{
		g->vertex[i] = (pVNode)malloc(sizeof(VNode));

		cin >> (g->vertex[i]->data);
		g->vertex[i]->first_arc = NULL;
	}
	cout << "输入" << g->arc_num << "个边和边的权重(比如:输入0 1 20表示下标为0和下标为1的顶点有一条边且权重为20)" << endl;
	for (i = 0; i < g->arc_num; i++)
	{
		int x, y, w;
		cin >> x >> y >> w;

		pArc temp1 = (pArc)malloc(sizeof(ANode));
		temp1->position = y;
		temp1->weight = w;
		/*将边增加到链接链表中*/
		temp1->next = g->vertex[x]->first_arc;
		g->vertex[x]->first_arc = temp1;

		if (direction == 0)//说明是无向图
		{
			pArc temp2 = (pArc)malloc(sizeof(ANode));
			temp2->position = x;
			temp2->weight = w;

			temp2->next = g->vertex[y]->first_arc;
			g->vertex[y]->first_arc = temp2;
		}

	}
}

void init_queue(Queue *q)
{
	/*构造哨兵节点*/
	pQNode x = (pQNode)malloc(sizeof(QNode));
	x->next = NULL;

	q->front = q->tail = x;
}

bool isempty_queue(Queue q)
{
	if (q.front->next == NULL)
		return true;
	return false;
}

void insert_queue(Queue *q, int e)
{
	pQNode x = (pQNode)malloc(sizeof(QNode));
	x->next = NULL;
	x->data = e;

	q->tail->next = x;
	q->tail = x;
}

bool delete_queue(Queue *q, int *e)
{
	if (isempty_queue(*q))
		return false;

	pQNode x = q->front->next;
	*e = x->data;
	q->front->next = x->next;

	if (x->next == NULL)//假设删除的是最后一个元素
		q->tail = q->front;
	free(x);
	return true;
}

void topologic_sort(Graphic g)
{
	int in[MAX_VERTEX] = { 0 };//用来记录每一个顶点的入度
	/*统计每一个顶点的入度*/
	for (int i = 0; i < g.vertex_num;i++)
	{
		pArc x = g.vertex[i]->first_arc;
		while (x != NULL)
		{
			in[x->position] += 1;
			x = x->next;
		}
	}

	Queue A, B;
	init_queue(&A);
	init_queue(&B);

	/*将入度为0的顶点增加A队列*/
	for (int i = 0; i < g.vertex_num; i++)
	{
		if (in[i] == 0)
			insert_queue(&A, i);
	}

	while ( !isempty_queue(A))
	{
		int position;
		delete_queue(&A, &position);
		insert_queue(&B, position);
		/*将全部以顶点A为起点的边的其他顶点的入度减1*/
		pArc y = g.vertex[position]->first_arc;
		while (y != NULL)
		{
			in[y->position] -= 1;
			if (in[y->position] == 0)
				insert_queue(&A, y->position);
			y = y->next;
		}
	}
	/*输出拓扑排序的结果*/
	while ( !isempty_queue(B) )
	{
		int position;
		delete_queue(&B, &position);
		cout << g.vertex[position]->data << " ";
	}
}

以上是关于拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章

拓扑排序代码:

使用 C# 代码实现拓扑排序

UVA10305 拓扑排序

【数据结构】请写出以下AOV网的拓扑排序序列

数据结构问题~啥图可以进行拓扑排序~啥图不能进行拓扑排序?

拓扑排序之变量序列代码