数据结构-图-拓扑排序

拓扑排序
如果从V->W有一条有向路径,则v一定排在w之前。满足次条件的顶点序列为拓扑序列。获得拓扑序的过程叫做拓扑排序
**AOV网:**用弧表示活动间优先关系的有向图成为顶点表示活动的网。 —>应用于学生排课
拓扑排序解决办法:
(1)在有向图中选择一个没有前驱的顶点输出;
(2)从图中删除该顶点和所有以它为尾的弧;

问题:将以下表示课程优先关系的有向图按拓扑排序输出。
话不多说,直接上完整代码。


#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>

typedef char VertexType; //相当于VertexType 为char[4]
#define INFINITY 65535 //最大值
#define MaxSize 50 //最大顶点个数
typedef enum{DG,DN,UDG,UDN}GrandKind;//有向图,有向网,无向图,无向网
typedef int VRType; //顶点关系类型,无权图用0或1,有权图,则为权值类型
typedef char InfoPtr;

typedef struct
{
	VRType adj;//对于无权图用0或1表示,1表示相邻,0表示不相邻;对于带权值得图存储权值
	InfoPtr * info;//该弧相关信息指针,与弧或边的相关信息
} ArcNode, AdjMatrix[MaxSize][MaxSize];

typedef struct //图的类型定义
{
	VertexType vex[MaxSize][4];//相当于char[MaxSize][4],用于储存顶点
	AdjMatrix arc; // 邻接矩阵,存储边或弧的信息
	int vexnum, arcnum;//顶点数和弧的数目
	GrandKind kind;//图的定义
}MGraph;

void CreateGraph(MGraph *N);//创建图
int LocateVertex(MGraph N, VertexType *v);//定位顶点的下标
void DestroyGraph(MGraph *N);
void DisplayGraph(MGraph N);

typedef struct
{
	int front;
	int rear;
	int queue[MaxSize];

}SeqQueue; //定义一个队列来存入度尾

void InitQueue(SeqQueue *SCQ)
{
	SCQ->front = SCQ->rear = 0;
}

int SeqQueueEmpty(SeqQueue SCQ)
/*判断队列是否为空,空返回1,不空返回0*/
{
	if (SCQ.front == SCQ.rear)
		return 1;
	else
	{
		return 0;
	}
}

int EnQueue(SeqQueue *SCQ, int e)
/*将元素e按入队列*/
{
	if ((SCQ->rear + 1) % MaxSize == SCQ->front)//队列已经满
		return 0;
	SCQ->queue[SCQ->rear] = e;
	SCQ->rear = (SCQ->rear + 1) % MaxSize;
	return 1;
}

int DeQueue(SeqQueue *SCQ, int *e)
/*队头出队列,成功返回1,失败返回0*/
{
	if (SCQ->front == SCQ->rear) //空队列
		return 0;
	else
	{
		(*e) = SCQ->queue[SCQ->front];
		SCQ->front = (SCQ->front + 1) % MaxSize;
		return 1;
	}
}


void FindIndegree(MGraph N, int Indegree[MaxSize])
/*求出各点的入度*/
{
	int v,i;
	int cnt;//计数入度的计数器
	for ( v= 0; v< N.vexnum; v++)
	{
		cnt = 0;
		for (i = 0; i< N.vexnum; i++)
		{
			if (N.arc[i][v].adj != INFINITY) //E(i,v)有弧
			{
				cnt++;
			}
		}
		Indegree[v] = cnt;
	}
}


void TopSort(MGraph N)
/*拓扑排序*/
{
	int Indegree[MaxSize];//记录各点入度的数组
	int Enqueued[MaxSize];//记录是否已经入队,初始化为0,如果入队为1
	FindIndegree(N, Indegree);//查找各个顶点的入度
	int i;
	int cnt;//记录有多少个点输出了
	int e;
	SeqQueue queue;
	InitQueue(&queue);//队列初始化
	for (i = 0; i < N.vexnum; i++)//初始化,入度为零的顶点进入队列
	{
		if (Indegree[i] == 0)
		{
			EnQueue(&queue, i);//下标为i的元素入队
			Enqueued[i] = 1;
		}
		else
		{
			Enqueued[i] = 0;
		}
	}

	cnt = 0;//初始化

	while (!SeqQueueEmpty(queue)) //队列元素不为空
	{
		DeQueue(&queue, &e);//队头元素出队
		printf(" 第%d个元素:%s \n", cnt+1,N.vex[e]);
		for (i = 0; i < N.vexnum; i++)
		{
			if (N.arc[e][i].adj < INFINITY)//对于e的每个邻接点
			{
				Indegree[i]--;//入度减一
			}
		}

		for (i = 0; i < N.vexnum; i++)//未进入队列且入度为零的顶点进入队列
		{
			if (Indegree[i] == 0 && Enqueued[i]==0)
			{
				EnQueue(&queue, i);//下标为i的元素入队
				Enqueued[i] = 1;//标记为进入了队列
			}
		}
		cnt++;
	}
	if (cnt != N.vexnum)
		printf("图中有环\n");

}
/*主函数*/
int main()
{
	MGraph N;
	int i,u;
	printf("创建无向网:\n");
	CreateGraph(&N);
	DisplayGraph(N);
	TopSort(N);
	

	return 0;
}

void CreateGraph(MGraph *N)
//
{
	int i,j,k,weight;
	VertexType v1[4], v2[4];
	printf("请输入有向网的顶点数和弧数(以逗号分开):\n");
	scanf_s("%d,%d", &(N->vexnum), &(N->arcnum));
	printf("请输入%d个顶点的值(<%d个字符)\n", N->vexnum, MaxSize);
	for (i = 0; i < N->vexnum; i++)//存储顶点
	{
		scanf_s("%s", N->vex[i],sizeof(N->vex[0]));
	}

	for (i = 0; i < N->vexnum; i++)// 初始化邻接矩阵
	{
		for (j = 0; j < N->vexnum; j++)
		{
			N->arc[i][j].adj = INFINITY;
			N->arc[i][j].info = NULL;
		}
	}

	printf("输入两个顶点和弧的权值(以空格隔开):\n");
	for (k = 0; k < N->arcnum; k++)
	{
		scanf_s("%s %s %d", v1,sizeof(4), v2,sizeof(4) ,&weight);
		i = LocateVertex(*N, v1);//找到弧尾顶点的下标
		j = LocateVertex(*N, v2);//找到弧顶顶点的下标
		N->arc[i][j].adj = weight;

	}
	N->kind = DN; //类型为有向网

}

int LocateVertex(MGraph N, VertexType *v)
//定位
{
	int  i;
	for (i = 0; i < N.vexnum; i++)
	{
		if (strcmp(N.vex[i],v)== 0)
			return i;
	}
	return -1;
}

void DestroyGraph(MGraph *N)
//销毁邻接表
{
	int i, j;
	for (i = 0; i < N->vexnum; i++)
	{
		for (j = 0; j < N->vexnum; j++)
		{
			if (N->arc[i][j].info != NULL)
			{
				free(N->arc[i][j].info);
				N->arc[i][j].info = NULL;
			}
		}
	}
	N->arcnum = N->vexnum = 0;

}

void DisplayGraph(MGraph N)
//显示邻接表
{
	int i, j, k;
	printf("输出网的结点和弧:\n");
	printf("该网有%d个顶点,%d条弧\n",N.vexnum,N.arcnum);
	printf("顶点依次是:");
	for (i = 0; i < N.vexnum;i++)
	{
		printf("%s ", N.vex[i]);
	}
	printf("网:\n");
	printf("  i=    ");
	for (i = 0; i < N.vexnum; i++)
	{
		printf("%8d", i);
	}
	printf("\n");
	for (i = 0; i < N.vexnum; i++)
	{
		printf("%8d", i);
		for (j = 0; j < N.vexnum; j++)
		{
			printf("%8d", N.arc[i][j].adj);
		}
		printf("\n");
	}

}

程序运行截图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38904904/article/details/89403073