7-1 拓扑排序
已知一个有向图,本题目要求完成拓扑排序算法7.12 。 顶点个数不超过30个。
输入格式:
输入分三部分:
第一行是图中顶点的个数、弧的条数
接着是每个顶点的信息
最后是每一条弧
输出格式:
输出的是顶点的拓扑序列,每个顶点后面有一个空格。不能完成拓扑排序的输出error
输入样例:
图7.28
6 8
v1
v2
v3
v4
v5
v6
v1 v4
v6 v4
v1 v2
v1 v3
v4 v5
v6 v5
v3 v2
v3 v5
输出样例:
v6 v1 v4 v3 v2 v5
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_VERTEX_NUM 31 // 最大顶点个数
#define OVERFLOW -1
#define FALSE 0;
#define TRUE 1
#define ERROR 0
#define OK 1
#define STACK_INIT_SIZE 100 //存储空间初始分配
#define STACKINCREMENT 10 //存储空间分配增量
typedef int Status;
typedef char VertexType[6];
// 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; 对带权图,则为权值类型
typedef int ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int SElemType;
typedef struct
{
SElemType *top;
SElemType *base;
int stacksize;
}SqStack;
Status InitStack(SqStack &s)
{s.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if (!s.base) exit(OVERFLOW); //存储分配失败
s.top=s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
Status GetTop(SqStack s, SElemType &e)
{ if(s.top==s.base) return ERROR;
e=*(s.top-1);
return OK;
}
Status Push(SqStack &s,SElemType e)
{//插入元素e为新的栈顶元素
if(s.top-s.base>=s.stacksize)
{//栈满,追加存储空间
s.base = (SElemType*)realloc(s.base, (s.stacksize+STACKINCREMENT)*sizeof(SElemType));
if(!s.base)exit(OVERFLOW); //存储分配失败
s.top = s.base + s.stacksize;
s.stacksize +=STACKINCREMENT;
}
*s.top++=e;
return OK;
}
Status Pop(SqStack &s,SElemType &e)
{ if(s.base==s.top) return ERROR;
e=*--s.top;
return OK;
}
Status StackEmpty(SqStack s)
{ if(s.base==s.top) return OK;
else return ERROR;
}
//图的邻接表存储表示
struct ArcNode
{
int adjvex; // 该弧所指向的顶点的位置
ArcNode *nextarc; // 指向下一条弧的指针
}; // 表结点
typedef struct
{
VertexType data; // 顶点信息
ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM]; // 头结点
struct ALGraph
{
AdjList vertices;
int vexnum,arcnum; // 图的当前顶点数和弧数
int kind; // 图的种类标志
};
int LocateVex(ALGraph G,VertexType u)
{ // 初始条件: 图G存在,u和G中顶点有相同特征
// 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
int i;
for(i=0;i<G.vexnum;++i)
if(strcmp(G.vertices[i].data,u)==0)
return i;
return -1;
}
Status CreateGraph(ALGraph &G)
{ //采用头插法,构造有向网
int i,j,k;
VertexType va,vb;
ArcNode *p;
//printf("请输入图的顶点数,弧数: ");
scanf("%d %d",&G.vexnum,&G.arcnum);
//printf("\n请输入%d个顶点的值:\n",G.vexnum);
for(i=0;i<G.vexnum;++i) // 构造顶点向量
{
scanf("%s",G.vertices[i].data);
G.vertices[i].firstarc=NULL;
}
for(k=0;k<G.arcnum;++k) // 构造表结点链表
{
scanf(" %s%s",va,vb);
i=LocateVex(G,va); // 弧尾
j=LocateVex(G,vb); // 弧头
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
p->nextarc=G.vertices[i].firstarc; // 插在表头
G.vertices[i].firstarc=p;
}
return OK;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ // 初始条件: 图G存在,v是G中某个顶点
// 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1
ArcNode *p;
int v1;
v1=LocateVex(G,v); // v1为顶点v在图G中的序号
p=G.vertices[v1].firstarc;
if(p)
return p->adjvex;
else
return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ // 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点
// 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。
// 若w是v的最后一个邻接点,则返回-1
ArcNode *p;
int v1,w1;
v1=LocateVex(G,v); // v1为顶点v在图G中的序号
w1=LocateVex(G,w) ; // w1为顶点w在图G中的序号
p=G.vertices[v1].firstarc;
while(p && p->adjvex!=w1) // 指针p不空且所指表结点不是w
p=p->nextarc;
if(!p||!p->nextarc) // 没找到w或w是最后一个邻接点
return -1;
else
return p->nextarc->adjvex; // 返回v的(相对于w的)下一个邻接顶点的序号
}
void Display(ALGraph G)
{ // 输出图的邻接矩阵G
int i;
ArcNode *p;
printf("%d个顶点:\n",G.vexnum);
for(i=0;i<G.vexnum;++i)
printf("%s ",G.vertices[i].data);
printf("\n%d条弧:\n",G.arcnum);
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
//输出结点以及其邻接结点数据
p=p->nextarc;
printf("\n");
}
}
}
void FindInDegree(ALGraph G,int a[31]){ //计算每一个结点的入度
ArcNode *p;
for(int i=0;i<G.vexnum;i++){
p=G.vertices[i].firstarc; //p为指向结点发出弧的指针
while(p!=NULL){
a[p->adjvex]++; //该点为一条弧的终点,数组自增,代表该弧指向的顶点的入度加一
p=p->nextarc; //p指向下一条弧
}
}
}
Status TopologicalSort(ALGraph G){
int indegree[31]={0};
SqStack S;
FindInDegree(G,indegree);
InitStack(S);
int count = 0;
for(int i=0;i<G.vexnum;i++){
if(!indegree[i])Push(S,i); //如果入度为0,i入栈
}
count = 0;
while(!StackEmpty(S)){
int e;
Pop(S,e); //入度为0的点出栈
printf("%s ",G.vertices[e].data); //输出入度为0的结点数据
count ++;
for(ArcNode* p=G.vertices[e].firstarc;p;p=p->nextarc){
int k=p->adjvex;
if(!(--indegree[k]))Push(S,k); //刚刚出栈的点所指向的点入度-1
}
}
if(count<G.vexnum)return ERROR;
else
return OK;
}
int main(){
ALGraph G;
CreateGraph(G);
if(TopologicalSort(G)==0)printf("error"); //排序失败则输出error
return 0;
}