邻接表的拓扑排序
本拓扑排序建立在之前博客建立邻接表的基础上进行排序,在之前建立邻接表的基础上在表头(表的第一列存点的信息)的基础上增加indegree变量用来表示每个点的度。拓扑排序主要思路:
(1)统计所有顶点的入度,接着把入度为0的全部入栈或者入队列(我用的是队列)。(2)取出栈顶元素,或者队列的首个元素,标记该顶点为"已访问"状态。(3)接着删除该顶点与其它顶点的联系,即把其它相邻顶点的入度减少1。相邻顶点中,入度减少1之后,如果存在入度为0的新顶点,把新顶点入栈或者入队列。直到全部点均遍历过。
图片来源
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
using namespace std;
#define max 110
queue<int>q;
typedef struct graphhead{//表头(表的第一列)用来存各个顶点信息
int indegree;//用来统计入度
int data;
struct node* next;
}List[max];//有多个顶点,所以用数组
struct node{//结构体节点,用来表示顶点的后继点的信息
int xuhao;//存后继点的序号(序号是用来找该后继点信息)
struct node* xuhaonext;//后继指针
};
struct graph{
int pnum,snum;//分别表示表中点的数量与边的数量
List list;//将表示各点信息的数组作成员可访问各个点的信息
};
void clear(graph* g,node* p)//
{
while(p!=NULL)
{
//id=findxuhao(g,p->xuhao);
g->list[p->xuhao].indegree--;
//for(int i=1;i<=g.pnum;i++)
//{
// if(id==)
// }
p=p->xuhaonext;
}
}
int findxuhao(graph* g,int id)//查找序号,id为一个点的名字(信息),查找该点在list中所处的编号
{
for(int i=1;i<=g->pnum;i++)
{
if(id==g->list[i].data)return i;
}
return -1;
}
void create(graph* g)//创建邻接表
{
int start,end,n,m;
printf("输入节点数,边数:\n");
scanf("%d%d",&g->pnum,&g->snum);
for(int i=1;i<=g->pnum;i++)
{
printf("请输入第%d个顶点的信息:\n",i);
scanf("%d",&g->list[i].data);
g->list[i].next=NULL;
}
for(int i=1;i<=g->pnum;i++)
g->list[i].indegree=0;
printf("请输入每条边的指向:\n");
for(int i=1;i<=g->snum;i++)
{
printf("第%d条边:\n",i);
scanf("%d%d",&start,&end);
m=findxuhao(g,start);
n=findxuhao(g,end);//查找指向点与被指向点的序号
if(m==-1||n==-1){
printf("建立失败!\n");break;
}
node* p=(node*)malloc(sizeof(node));
g->list[n].indegree++;
p->xuhao=n;//头插法插入新建的指针
p->xuhaonext=g->list[m].next;
g->list[m].next=p;
}
}
void PrintLink(graph* g ,node* xuhaonext) {//打印出该点指向的所有点
while (xuhaonext!= NULL) {
printf("%4d",g->list[xuhaonext->xuhao].data);
xuhaonext = xuhaonext->xuhaonext;
}
printf("\n");
}
void disp(graph* g) {//按序号顺序打印出各个点的信息
printf("邻接表:\n");
for (int i = 1; i <= g->pnum; i++) {
printf("%4d",g->list[i].data);
PrintLink(g,g->list[i].next);
}
}
void topo(graph* g)//拓扑排序
{
printf("拓扑排序为:\n");
int cout=0;//cout计数输出点个数
while(cout < g->pnum)// 点全部输出完结束
{
for(int i=1;i<=g->pnum;i++)
{
if(g->list[i].indegree==0){//入度为0时进队
q.push(i);
g->list[i].indegree--;//该点的度--
break;
}
}
printf("%4d",g->list[q.front()].data);
clear(g,g->list[q.front()].next);//输出一个度为0的点,更新该点全部后继点的度
q.pop();
cout++;
}
}
int main()
{
graph* g=(graph*)malloc(sizeof(graph));
create(g);
disp(g);
printf("\n");
topo(g);
return 0;
}