【数据结构】拓扑排序

news/2024/7/5 4:02:17

如果一个有向图中没有包含简单的回路,这样的图为有向无环图。

图中的顶点代表事件(活动),图中的有向边说明了事件之间的先后关系。这种用顶点表示活动,用弧表示活动时间的优先关系的有向图称为顶点表示活动的网,简称AOV网(Active On Vertex Network)。

在AOV网中,若顶点u与顶点v之间存在一条有向边<u,v>,则说明事件u必须先于事件v完成。此处将u称为v的直接前驱,v称为u的直接后继。

对AOV网进行拓扑排序的方法和步骤如下:

(1)在有向图中找一个没有前驱(入度为0)的顶点并输出。

(2)在图中删除该顶点以及所有与该顶点出发的有向边。

(3)反复执行步骤(1)和步骤(2),直到所有顶点均被输出,或者AOV网中再也没有入度为0的顶点存在为止。

算法的两种结束情况:

(1)所有顶点全部输出,表明对该图的拓扑排序成功。

(2)图中有部分结点没有输出,但已经不存在入度为0的顶点,说明此AOV网中存在环。

 

直接输入(真的好麻烦,输错一个就要重来)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>const int M = 20;typedef struct node
{int adjvex;struct node *next;
}edgenode;typedef struct de //带顶点入度的头节点定义
{edgenode *FirstEdge;char vertex;int id;//顶点的入度
}vertexnode;typedef struct //AOV网的邻接表结构
{vertexnode adjlist[M];int n,e;
}AovGraph;//创建AOV网络的邻接表
void creat(AovGraph *g)
{int i,j,k;edgenode *s;printf("请输入点数和边数:");scanf("%d%d",&g->n,&g->e);getchar();printf("\n请输入顶点序号以及该顶点入度:\n");for(i=0;i<g->n;i++){scanf("%c",&g->adjlist[i].vertex);scanf("%d",&g->adjlist[i].id);getchar();g->adjlist[i].FirstEdge=NULL;}printf("\n请输入有向边:\n");for(k=0;k<g->e;k++){scanf("%d%d",&i,&j);s=(edgenode*)malloc(sizeof(edgenode));s->adjvex=j;s->next=g->adjlist[i].FirstEdge;g->adjlist[i].FirstEdge=s;}
}//打印AOV网络的邻接表
void print(AovGraph g)
{int i,j,k;edgenode *p;for(i=0;i<g.n;i++){printf("入度:%d 地址:%d char值:C%c->  ",g.adjlist[i].id,i,g.adjlist[i].vertex);p=g.adjlist[i].FirstEdge;if(p == NULL){printf("NULL\n");continue;}while(p){printf("%d",p->adjvex);if(p->next){printf(" -> ");}p=p->next;}printf("\n");}return ;
}//拓扑排序算法
int TopSort(AovGraph g)
{int k=0,i,j,v,flag[M];int queue[M];int front ,rear;edgenode *p;front = 0;rear = 0;memset(flag,0,sizeof(flag));//访问标记初始化for(i=0;i<g.n;i++){if(g.adjlist[i].id==0 && flag[i]==0){queue[rear++]=i;flag[i]=1;}}printf("\nAOV网的拓扑排序为:\n");while(front < rear)//当队列空间不为空时{v = queue[front++];//队首元素出队printf("%c ",g.adjlist[v].vertex);k++;//计数器加一p=g.adjlist[v].FirstEdge;while(p)//将所有与v邻接的顶点的入度减一{j=p->adjvex;if(--g.adjlist[j].id==0 && flag[j]==0){queue[rear++]=j;flag[j]=1;}p=p->next;}}return k;
}int main ()
{int node_num;AovGraph g;creat(&g);print(g);node_num=TopSort(g);printf("\n一共输出%d个结点\n",node_num);if(g.n==node_num)printf("所有顶点全部输出,对该图拓扑排序成功!\n");elseprintf("此AOV网中存在着环,无法完成拓扑排序!\n");return 0;
}

  

 

使用文件读取数据(十分方便)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>const int M = 20;typedef struct node
{int adjvex;struct node *next;
}edgenode;typedef struct de //带顶点入度的头节点定义
{edgenode *FirstEdge;char vertex;int id;//顶点的入度
}vertexnode;typedef struct //AOV网的邻接表结构
{vertexnode adjlist[M];int n,e;
}AovGraph;//创建AOV网络的邻接表
void creat(AovGraph *g)
{int i,j,k;edgenode *s;FILE *f;f=fopen("test.txt","r");if(f){fscanf(f,"%d%d",&g->n,&g->e);for(i=0;i<g->n;i++){fscanf(f,"%1s %d",&g->adjlist[i].vertex,&g->adjlist[i].id);g->adjlist[i].FirstEdge=NULL;}for(k=0;k<g->e;k++){fscanf(f,"%d%d",&i,&j);s=(edgenode*)malloc(sizeof(edgenode));s->adjvex=j;s->next=g->adjlist[i].FirstEdge;g->adjlist[i].FirstEdge=s;}fclose(f);}else{g->n=0;}
}//打印AOV网络的邻接表
void print(AovGraph g)
{int i,j,k;edgenode *p;for(i=0;i<g.n;i++){printf("入度:%d 地址:%d char值:C%c->  ",g.adjlist[i].id,i,g.adjlist[i].vertex);p=g.adjlist[i].FirstEdge;if(p == NULL){printf("NULL\n");continue;}while(p){printf("%d",p->adjvex);if(p->next){printf(" -> ");}p=p->next;}printf("\n");}return ;
}//拓扑排序算法
int TopSort(AovGraph g)
{int k=0,i,j,v,flag[M];int queue[M];int front ,rear;edgenode *p;front = 0;rear = 0;memset(flag,0,sizeof(flag));//访问标记初始化for(i=0;i<g.n;i++){if(g.adjlist[i].id==0 && flag[i]==0){queue[rear++]=i;flag[i]=1;}}printf("\nAOV网的拓扑排序为:\n");while(front < rear)//当队列空间不为空时{v = queue[front++];//队首元素出队printf("%c ",g.adjlist[v].vertex);k++;//计数器加一p=g.adjlist[v].FirstEdge;while(p)//将所有与v邻接的顶点的入度减一{j=p->adjvex;if(--g.adjlist[j].id==0 && flag[j]==0){queue[rear++]=j;flag[j]=1;}p=p->next;}}return k;
}int main ()
{int node_num;AovGraph g;creat(&g);print(g);node_num=TopSort(g);printf("\n一共输出%d个结点\n",node_num);if(g.n==node_num)printf("所有顶点全部输出,对该图拓扑排序成功!\n");elseprintf("此AOV网中存在着环,无法完成拓扑排序!\n");return 0;
}

 


http://lihuaxi.xjx100.cn/news/251438.html

相关文章

2021-2022-1 线性代数知识点总结的视频

01 线性方程组02 矩阵及其运算03 向量空间&#xff08;上&#xff09;03 向量空间&#xff08;下&#xff09;04 特征值与特征向量05 实对称矩阵与二次型2021 线性代数 第三章 习题课2021 线性代数 第四章 习题课2021-2022-1 线性代数考试要点2021-2022-1 线性代数知识点总结 …

linux sntp 代码,C语言window(linux)平台的SNTP实现

C语言实现window(linux)平台的SNTP&#xff0c;本程序功能主要是实现电脑(或者设备)时间同步。摘录部分代码&#xff1a;unsigned char liVnMode; /* LeapSecond(2bits:0), VersionNumber(3bits: 3), Mode(3bits: Client3, Server4) */unsigned char stratum; /* 时间层级 (0-1…

消息服务发送短信,手机接收不到短信解决思路

阿里云使用消息服务&#xff0c;发送注册码给手机。测试几次发现手机都接收不到&#xff0c;后台也没报错&#xff01;今天我提交自己的工单&#xff0c;售后工程师已经帮我解决了&#xff0c;非常感谢他&#xff01;官方代码&#xff1a;https://help.aliyun.com/document_det…

【数据结构】关键路径

在有向图中&#xff0c;如果用顶点表示事件&#xff0c;弧表示活动&#xff0c;弧上的权值表示活动持续的时间&#xff0c;这样的活动称为边表示活动的网&#xff0c;简称AOE网&#xff08;Activity On Edge&#xff09;。通常可以用AOE网来估算工程的完成时间&#xff0c;他不…

VC:其他控件(CProgressCtrl、CScrollBar、CDateTimeCtrl、CMonthCalCtrl)

1、进度条 m_progressCtrl.SetRange(0,100); for(int i0;i<100;i) { m_progressCtrl.SetPos(i); Sleep(100); } AfxMessageBox("进度条到达终点"); 2、滑块控件&#xff1a;添加WM_VSCROLL消息。 void COtherCtrlDlg::OnHScroll(UINT nSBCode, UINT nPos, CScroll…

linux孤立cpu,Linux 抛弃旧款 CPU,一下子少 50 万行代码

IT 之家4 月 3 日消息 Linux 内核维护者已经决定在即将发布的新版本中抛弃对旧款 CPU 架构的支持&#xff0c;因此 Linux 4.17 内核将减少大约 500000 行代码&#xff0c;根据 Linux 统计器&#xff0c;目前它包含大约 2030 万行代码。IT 之家报道&#xff0c;将被弃用的体系架…

SpringBoot 中 JPA 的使用

前言 第一次使用 Spring JPA 的时候&#xff0c;感觉这东西简直就是神器&#xff0c;几乎不需要写什么关于数据库访问的代码一个基本的 CURD 的功能就出来了。下面我们就用一个例子来讲述以下 JPA 使用的基本操作。 新建项目&#xff0c;增加依赖 在 Intellij IDEA 里面新建一个…

【组队学习】【32期】推荐系统-新闻推荐系统实践

推荐系统-新闻推荐系统实践 航路开辟者&#xff1a;罗如意领航员&#xff1a;肖桐航海士&#xff1a;汪志鸿、吴忠强、赖敏材、王辰玥、毛伟、宋禹成、陈雨龙、管柯琴 基本信息 开源内容&#xff1a;https://github.com/datawhalechina/fun-rec内容属性&#xff1a;公测课程…