根据用户输入的偶对(以输入0表示结束)建立其有向图的邻接表,并输出其一个拓扑排序序列和逆拓扑排序,并判断是否有回路

根据用户输入的偶对(以输入0表示结束)建立其有向图的邻接表,
并输出其一个拓扑排序序列和逆拓扑排序,并判断是否有回路 

top代码:

//拓扑排序
int top[size] = {0};//保存 拓扑排序结果 方便逆拓扑 
int topsort(listnode a[])
{
	stack<int>s1;
	node *q;
	for(int i = 0;i < size;i ++)
	{
		if(a[i].indegree == 0)//遍历表结点,所有入度为0的都进栈 
		{
			s1.push(a[i].index);//表结点 下标进栈 
		}
	}
	int count = 0;//顶点的 计数器,如果count小于结点数,说明有环 
	
	int j;//保存此时 要处理的表结点下标
	while(s1.empty() != 1)//栈不为空 
	{
		j = s1.top();//取栈顶 元素的下标(本次处理结点的下标) 
		s1.pop();//出栈 
		
		//printf("%5d",a[j - 1].index);//打印 该结点下标,此为为拓扑序列一部分 
		top[count] = a[j - 1].index;//保存 该结点下标,此为为拓扑序列一部分 
		count ++;//该结点满足条件,成功顶点数 + 1 
		
		//数组的下标为 结点下标-1(数组从0开始编号,结点从1开始编号) 
		q = a[j - 1].first;//保存为 所取下标的 顶点结点(与其相连的 结点 入度-1)
		
		int k = 0;//k保存要处理结点的 下标 
		while(q != NULL)//如果该顶点有与它相连的结点 
		{
			k = q->aimdex;//k要处理结点的 下标 
			
			//数组的下标为 结点下标-1(数组从0开始编号,结点从1开始编号) 
			a[k - 1].indegree --;  //该结点入度减1(因为与之相连的j已经处理) 
			if(a[k - 1].indegree == 0)//如果 减一后度为0说明 是待处理对象 把其下标入栈 
			{
				s1.push(k);//入栈 该下标 
			}
			q = q->next;//看是否还有 与j 相连的结点,q继续遍历j的边结点 
		} 
	}
	
	if(count < size)//如果有结点没有经过 进栈出栈(没有处理到count != size) 
	{
		printf("the graph has recycle");
		return -1;//说明 拓扑排序失败 
	}
	
	return 1; //说明 拓扑排序成功 
}

完整code:

/*
根据用户输入的偶对(以输入0表示结束)建立其有向图的邻接表,
并输出其一个拓扑排序序列和逆拓扑排序,并判断是否有回路 
*/

#include <stdio.h>
#include <malloc.h>
#include <stack>
#define size 6
using namespace std;
typedef struct node{
	int aimdex;//箭头指向结点的编号 
	struct node *next;//指向下一个结点 
}node;

typedef struct listnode{
	int index;   //结点编号 
	int indegree;//入度
	int outdegree;//出度 
	node *first; //第一个 边结点 (用 头插法 建立)
}listnode;

//构建 邻接表,同时统计 每个结点的 出度 
int len = sizeof(node);//便于 申请 结点空间 
void create_list(listnode a[])
{
	listnode *p = a;//表结点 
	node *q;//指向边结点 
	//初始 N个 表结点 
	for(int i = 0;i < size;i ++)
	{
		p[i].index = i + 1;//1~n编号
		p[i].indegree = 0;
		p[i].outdegree = 0;
		p[i].first = NULL;
	}
	
	//建立 边结点 
	printf("\nplease input the edge node(箭头尾部&头部(编号)(0,0)为结束):\n");
	int k = 0,m = 0;
	scanf("%d%d",&k,&m);//k为 有向边,箭头尾部,m为 头部,编号 
	
	while(k != 0 && m != 0)//输入(0,0)结束
	{
		q = (node*)malloc(len);
		
		q->aimdex = m;//标识所指 结点编号 
		//头插法 思想 
		q->next = p[k - 1].first;//本次结点next 指向上次插入的那个结点(没有就指向 NULL) 
		p[k - 1].first = q;//头插法 新的 边结点 插入单链表的表头 
		
		p[k - 1].outdegree ++;//出度 增加
		p[m - 1].indegree ++;//入度 增加
		
		scanf("%d%d",&k,&m);
	}
	return;
}

//拓扑排序
int top[size] = {0};//保存 拓扑排序结果 方便逆拓扑 
int topsort(listnode a[])
{
	stack<int>s1;
	node *q;
	for(int i = 0;i < size;i ++)
	{
		if(a[i].indegree == 0)//遍历表结点,所有入度为0的都进栈 
		{
			s1.push(a[i].index);//表结点 下标进栈 
		}
	}
	int count = 0;//顶点的 计数器,如果count小于结点数,说明有环 
	
	int j;//保存此时 要处理的表结点下标
	while(s1.empty() != 1)//栈不为空 
	{
		j = s1.top();//取栈顶 元素的下标(本次处理结点的下标) 
		s1.pop();//出栈 
		
		//printf("%5d",a[j - 1].index);//打印 该结点下标,此为为拓扑序列一部分 
		top[count] = a[j - 1].index;//保存 该结点下标,此为为拓扑序列一部分 
		count ++;//该结点满足条件,成功顶点数 + 1 
		
		//数组的下标为 结点下标-1(数组从0开始编号,结点从1开始编号) 
		q = a[j - 1].first;//保存为 所取下标的 顶点结点(与其相连的 结点 入度-1)
		
		int k = 0;//k保存要处理结点的 下标 
		while(q != NULL)//如果该顶点有与它相连的结点 
		{
			k = q->aimdex;//k要处理结点的 下标 
			
			//数组的下标为 结点下标-1(数组从0开始编号,结点从1开始编号) 
			a[k - 1].indegree --;  //该结点入度减1(因为与之相连的j已经处理) 
			if(a[k - 1].indegree == 0)//如果 减一后度为0说明 是待处理对象 把其下标入栈 
			{
				s1.push(k);//入栈 该下标 
			}
			q = q->next;//看是否还有 与j 相连的结点,q继续遍历j的边结点 
		} 
	}
	
	if(count < size)//如果有结点没有经过 进栈出栈(没有处理到count != size) 
	{
		printf("the graph has recycle");
		return -1;//说明 拓扑排序失败 
	}
	
	return 1; //说明 拓扑排序成功 
}

/*
test_one(测试环的情况) 
结点编号  边结点         indegree(入度)    outdegree(出度)
1        -->4-->3-->2    1                 3
2        -->5            2                 1
3        -->5-->2        1                 2
4        -->5            2                 1
5        -->1            4                 1
6        -->5-->4        0                 2

test_one(测试无环的情况) 
结点编号  边结点         indegree(入度)    outdegree(出度)
1        -->2            0                 1
2        -->3            1                 1
3        -->4            1                 1
4        -->5            1                 1
5        -->6            1                 1
6                        1                 0
*/
//打印拓扑排序(或逆拓扑排序) 数组 
void print_array(int a[],int flag)
{
	if(flag == 0)//打印拓扑 排序 
		for(int i = 0;i < size;i ++)
		{
			printf("%d ",a[i]);
		}
	else//逆拓扑排序(拓扑排序反转输出) 
		for(int i = size - 1;i >= 0;i --)
		{
			printf("%d ",a[i]);
		}
	printf("\n");
}
int main()
{
	listnode a[size];
	//构建 邻接表,同时统计 每个结点的 出度 
	create_list(a);
	
	//拓扑排序
	int flag = topsort(a);
	if(flag == 1)//如果没有环,top排序成功 
	{
		printf("拓扑排序结果:");
		print_array(top,0);
		
		//逆拓扑排序
		printf("逆拓扑排序结果:");
		print_array(top,1);//逆拓扑排序(拓扑排序反转输出) 
	}
	else;
	
	
	return 0;
}

无环情况测试:

有环情况测试:

 

Guess you like

Origin blog.csdn.net/qq_47991812/article/details/121439987