拓扑排序

         拓扑排序属于有向无环图的应用,在实际工作中,长长把用一个有向图来表示工程的施工流程图,或者产品生产的流程图。一个工程一般可以分为若干个子工程,通常把子工程称为“活动”。有些应用关心工程是否能够顺利完成,即是否存在一个从工程开始到工程完成的活动序列,该序列满足所有活动之间的制约关系(一些活动的开始必须以另一个活动的结束为条件);而有些关系的是,工程的完成时间的估算,哪些活动是影响工程进度的关键。对于两种不同的要求有向图提供了两类支持:一个是拓扑序列和逆拓扑序列,第二个就是关键路径。

第一个拓扑序列是以顶点为活动的有向图(成AOV网)为基础,在AOV网中一定不能存在回路,构造AOV网的拓扑有序序列的运算称为拓扑排序(完全不同于传统的键值排序)排序后的序列即为拓扑序列。

基本思想如下: 在AOV网中至少存在有一个入度为0的点(没有前驱的顶点,没有被制约的定点),首先找到一个入度为0的顶点输出他,并删除它所发出的所有有向边(这样做可能会产生新的入度为0的点);继续寻诈骗下一个入度为0的顶点进行输出,并删除它所发出的所有的有向边;....;重复上述动作知道再也找不到一个入度为0的顶点为止。

得到两种结果:1 若拓扑有序序列包含了AOV网所有的顶点(AOV网的所有顶点均被输出),则说明AOV网中不存在有向回路(拓扑排序成功);

       2 拖拓扑有序序列没有包含AOV网所有的顶点(AOV网中的顶点没有全部输出,剩余的顶点均有前驱顶点),则说明AOV网中存在有向回路(排序失败)。

注:拓扑序列并不是唯一的,同一组活动制约不同的方法可以得到不同的拓扑序列

下面是基本的实现代码,建议自己亲手尝试下肯定会有很多的收获,因为这个程序的数据结构比较复杂,需要注意的地方很多。

/*

拓扑排序:基于邻接表的拓扑排序
作者:chongge

*/

#include <iostream>

const int MAX = 100;

typedef char VertexType;
typedef int  ElemType;

typedef struct EdgeNode
{
	int adjno;				//后继链表
	struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode	//邻接表元素
{
	VertexType data;		//顶点标识
	EdgeNode *first;		//后继链表起点
}VertexNode;

typedef struct
{
	VertexNode vexs[MAX];	//邻接表数组
	int vexnum;				//记录图的定点数
	int arcnum;				//弧的条数
}AdList;

/*求AOV网的各顶点的入度*/
void GetInDegree(AdList *AOV,int indegree[])
{
	EdgeNode *p= NULL;
	for(int i= 1 ;i <=AOV->vexnum ; i++)
	{
		p = AOV->vexs[i].first;
		while(p != NULL)
		{
			indegree[p->adjno] ++ ;
			p = p->next;
		}
	}
}



int TopSort(AdList *AOV)
{
	int stack[MAX];
	int top = 0 ;		//作为简易栈使用
	EdgeNode *p = NULL;
	int indegree[MAX];
	for(int i=1; i<=AOV->vexnum; i++)
		indegree[i] = 0;
	GetInDegree(AOV,indegree);

	for(int i=1; i<=AOV->vexnum ;i++)
		if(indegree[i] == 0)
			stack[++ top] = i;
	int cnt =0;
	while(top > 0)
	{
		int i = stack[top --];
		std::cout << i << " ";
		cnt ++;
		p = AOV->vexs[i].first;
		while(p != NULL)
		{
			indegree[p->adjno] --;
			if(indegree[p->adjno] == 0)
				stack[++top] = p->adjno;
			p = p->next;
		}
	}

	if(cnt < AOV->vexnum)
	{
		std::cout << "TopSort failed" << std::endl;
		delete AOV;
		return -1;
	}

	std::cout << "TopSort success" << std::endl;
	delete AOV;			//排序完了之后删除,避免内存泄漏
	return 0;
}

AdList * CreateVextexList(int Nodenum)
{
	AdList *AOV = new AdList;
	for(int i=0; i<=Nodenum ;i++)			//使用一个专门的初始化函数更好
	{	
	//	AOV->vexs[i].first = new EdgeNode;
		AOV->vexs[i].first = NULL;

	}
	VertexType elem;
	int m;
	int n;
	int edge = 0;
	AOV ->vexnum = Nodenum ;					//顶点个数
	while(Nodenum --)
	{
		std::cin >>elem >> m >> n;			//表示m要在n之前完成
		edge ++;
		if( (m+n) != 0)
			AOV->vexs[m].data = elem ;
/*	
	特别注意下面这个p使用的是双重指针,需要解释一下,
	这个first为指向另一个结构体的指针,保存的是指针
	的地址,将first赋给p,p的值和first相同,这是个
	复制过程也就是说p是first的一个副本,所以当后面
	p = q执行时,q的值又复制给q,此时p的值虽然改变
	了,但是first值确不会变,所以需要一个指向first
	的值的指针,即指向指针的指针,这时赋值后的值就
	是直接改变p指向的值
*/
		EdgeNode **p = &AOV->vexs[m].first;	
		EdgeNode *q = new EdgeNode;		
		q->adjno = n;					//表示m指向n
		q->next = NULL;
		if( *p == NULL)					//头插法
			*p = q ;
//			pp = qq;					//指向指针的指针赋值指针的地址
		else
		{
			q->next = (*p)->next;			//每次查到first的后面
			(*p)->next = q;
		}
	}
	AOV ->arcnum = edge ;			//边的条数
	return AOV;
}


int main()
{
	AdList *AOV = NULL;
	int Nodenum;
	std::cin >>Nodenum ;
	AOV = CreateVextexList(Nodenum);
	TopSort(AOV);
	//GetInDegree(AOV);
}
没有全部验证,如果出现错误,请留言指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值