数据结构之图的拓扑排序

图的拓扑排序

       图的拓扑排序理解起来很简单,一个简单易懂的定义:将有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边<u,v>,在最后的排序结果中,顶点u总是在顶点v的前面。

      介绍图的拓扑排序之前需要介绍偏序和全序的概念,在这里我只说说我的理解。



       我们规定有向图入度为零的顶点才可以被访问,则图a中的部分顶点存在着先后关系,很明显V2和V3不存在先后关系,它们之间不可以比较,这种关系为偏序。而图b中每一个顶点都可以比较,这种关系为全序关系。

      如果一个图为全序关系,我们可以简单的从入度为零的顶点顺着边的方向挨个访问顶点即可。而我们需要解决的是具有偏序关系的图,当我们人为的在V2和V3之间加上一个V2<=V3的弧,则图a表示的亦为全序,且这个全序称为拓扑有序,而由偏序定义得到拓扑有序的操作便是拓扑排序。


     拓扑排序的实现方法有很多种,可以使用队列或是栈从入度角度或是出度的角度出发,或者简单的使用一个数组存放顶点的访问顺序也可以。
    在这里我从顶点的入度出发。首先有向图,使用邻接表来存储,邻接表的头结点有两个数据域一个用来存储顶点的入度,一个为指向表结点的指针。表结点和头节点公用一个结构,只是存储入度的数据域改为用来存储头节点所指结点在图中的序号。

typedef struct vertex{
	int iInDegree;                     //头结点中表示顶点的入度,表结点中表示顶点的序号
	struct vertex * pNext;
}VERTEX;

typedef struct {
	VERTEX * pVertex;
	int iVexNum;
}GRAPH;


以上图为例,我们做它的拓扑排序。

算法流程:


实现代码:
#include <stdio.h>
#include <malloc.h>

#define MAX_VEX_NUN 100

typedef struct vertex{
	int iInDegree;                     //头结点中表示顶点的入度,表结点中表示顶点的序号
	struct vertex * pNext;
}VERTEX;

typedef struct {
	VERTEX * pVertex;
	int iVexNum;
}GRAPH;

void CreateGraph(GRAPH * pGraph)
{
	int iVexNum;
	int iLinkNum;
	int iVexOrder;
	VERTEX * pNext;

	printf("输入顶点数量:");
	scanf_s("%d", &iVexNum);

	pGraph->pVertex = (VERTEX *)malloc(sizeof(VERTEX)*iVexNum);
	pGraph->iVexNum = iVexNum;

	for (int i = 0;i < iVexNum;i++)
	{
		pGraph->pVertex[i].iInDegree = 0;
		pGraph->pVertex[i].pNext = NULL;
	}

	for (int i = 0;i < iVexNum;i++)
	{
		printf("输入第%d个顶点指向其他顶点的数量:", i + 1);
		scanf_s("%d", &iLinkNum);
		if (iLinkNum != 0)
		{
			printf("输入这些被指向顶点的序号:");
			for (int j = 0;j < iLinkNum;j++)
			{
				scanf_s("%d", &iVexOrder);

				pNext = (VERTEX *)malloc(sizeof(VERTEX));
				pNext->iInDegree = iVexOrder - 1;
				pGraph->pVertex[iVexOrder - 1].iInDegree++;

				pNext->pNext = pGraph->pVertex[i].pNext;
				pGraph->pVertex[i].pNext = pNext;
			}
		}
	}

}

int TopSort(GRAPH * pGraph,int * pSorted)
{
	int iVexCnt = 0;
	int iVisitedCnt = 0;
	VERTEX * pNext;

	for (int i = 0;i < pGraph->iVexNum;i++)
	{
		if (pGraph->pVertex[i].iInDegree == 0)
			pSorted[iVexCnt++] = i;
	}

	while (iVisitedCnt != iVexCnt)
	{
		pNext = pGraph->pVertex[pSorted[iVisitedCnt++]].pNext;
		for (;pNext != NULL;pNext = pNext->pNext)
		{
			if ((--pGraph->pVertex[pNext->iInDegree].iInDegree) == 0)
				pSorted[iVexCnt++] = pNext->iInDegree;
		}
	}
	return iVexCnt;
}

int main(void)
{
	GRAPH Graph;
	int Sorted[MAX_VEX_NUN];

	CreateGraph(&Graph);

	if (Graph.iVexNum == TopSort(&Graph, Sorted))
		for (int i=0;i < Graph.iVexNum;i++)
			printf("%3d", Sorted[i]+1);
	else
		printf("此图有回路,无法进行拓扑排序。");

	return 0;
}
    TopSort()函数返回找到的入度为零的顶点的个数,通过比较返回的个数和图的所有顶点个数,可以判断这张图是否为有环图。

   以上图为例的输出结果:

平台:window10 vs2015

完整工程代码下载:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值