#include<stdio.h>
#include<stdlib.h>
#define MaxVertexNum 100
//下面构造工具栈
typedef int SElemType;
#define STACK_INIT_SIZE 10 //存储空间初始分配量
#define STACKINCREMENT 2 //存储空间分配增量
typedef struct SqStack
{
int *base;//基指针
int *top;//栈顶指针
int stacksize;
}SqStack;//栈的结构体定义
//构造一个空栈
int InitStack(SqStack *S)
{
//为栈底分分配一个指定大小的存储空间
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!(*S).base)
exit(0);
(*S).top = (*S).base; //栈底与栈顶指针同样
(*S).stacksize = STACK_INIT_SIZE;
return 1;
}
//若栈S为空栈(栈底指针和栈顶指针同样), 则返回1。否则返回0
int StackEmpty(SqStack S)
{
if(S.top == S.base)
return 1;
else
return 0;
}
//插入元素e为新的栈顶元素
int Push(SqStack *S, SElemType e)
{
if((*S).top - (*S).base >= (*S).stacksize)
{
(*S).base = (SElemType *)realloc((*S).base,((*S).stacksize + STACKINCREMENT)*sizeof(SElemType));
if(!(*S).base)
exit(0);
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++= e;
return 1;
}
//若栈不为空,则删除S栈顶元素用e返回其值。并返回1。否则返回0
int Pop(SqStack *S, SElemType *e)
{
if((*S).top == (*S).base)
{
return 0;
}
*e = *--(*S).top;
return 1;
}
typedef struct ArcNode//边表结点
{
int adjvex;//该弧指向的顶点的位置
struct ArcNode *nextarc;
}ArcNode;
typedef struct VNode//顶点结点
{
int data;
ArcNode *firstarc;
}VNode,AdjList[MaxVertexNum];
typedef struct
{
AdjList vertices;//邻接表
int vexnum,arcnum;
int kind;//图的类型(有向图,无向图)
}ALGraph;
int LocateVex(ALGraph G,int u)//返回顶点在图中的位置
{
int i;
for(i = 0; i < G.vexnum; ++i)
{
if(u==G.vertices[i].data)
return i;
return -1;
}
}
int CreateGraph(ALGraph *G)
{
ArcNode *p;
int i,j,k;
int va,vb;//弧尾和弧头
printf("请输入图的类型:(有向图:0 无向图:2)\n");
scanf("%d",&(*G).kind);
printf("请输入图的顶点数和边数,中间以空格间隔:\n");
scanf("%d%d",&(*G).vexnum,&(*G).arcnum);
printf("请连续输入%d个顶点的值: ",(*G).vexnum);
for(i=0;i<(*G).vexnum;++i)//建立顶点节点单链表
{
scanf("%d",&(*G).vertices[i].data);
(*G).vertices[i].firstarc=NULL;
}
printf("请顺序输入每条边的弧尾和弧头,以空格作为间隔:\n");//建立边结点链表
for(k=0;k<(*G).arcnum;++k)
{
scanf("%d%d",&va,&vb);
// i=LocateVex(*G,va);//弧尾
// j=LocateVex(*G,vb);//弧头
i=va-1;
j=vb-1;
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
p->nextarc=(*G).vertices[i].firstarc;
(*G).vertices[i].firstarc=p;
if((*G).kind>=2)//如果是无向图
{
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=i;
p->nextarc=(*G).vertices[j].firstarc;
(*G).vertices[j].firstarc=p;
}
}
return 1;
}
void Display(ALGraph G)
{
int i;
ArcNode *p;
switch(G.kind)
{
case 0:
printf("这是一个有向图!\n");
break;
case 2:
printf("这是一个无向图!\n");
break;
}
printf(" %d 个顶点分别为:\n",G.vexnum);
for(i = 0; i < G.vexnum; ++i)
{
printf("%d\t",G.vertices[i].data);
}
printf("\n");
printf(" %d 条边:\n",G.arcnum);
if(G.kind==0)//当是有向图时
{
for(i = 0; i < G.vexnum; i++)
{
p=G.vertices[i].firstarc;
while(p)
{
// if(i<p->adjvex)
// {
printf("%d-->%d\t",G.vertices[i].data,G.vertices[p->adjvex].data);
// }
p=p->nextarc;
}
printf("\n");
}
}
else if(G.kind==2)//是无向图时
{
for(i = 0; i < G.vexnum; i++)
{
p=G.vertices[i].firstarc;
while(p)
{
if(i<p->adjvex)
{
printf("%d-->%d\t",G.vertices[i].data,G.vertices[p->adjvex].data);
printf("%d-->%d\t",G.vertices[p->adjvex].data,G.vertices[i].data);
}
p=p->nextarc;
}
printf("\n");
}
}
}
void FindIndegree(ALGraph G,int indegree[])//计算顶点的入度
{
int i;
ArcNode *p;
for(i=0;i<G.vexnum;i++)
{
indegree[i]=0;
}
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;//每个头节点
while(p)
{
indegree[p->adjvex]++;//遍历整个邻接表
p=p->nextarc;
}
}
printf("各结点的入度为:\t");
for(i=0;i<G.vexnum;i++)
{
printf("%d\t",indegree[i]);
}
printf("\n");
}
//有向图采用邻接表储存,如果没有回路,则可以输出G的一个拓扑排序
bool TopologicalSort(ALGraph G)
{
SqStack s;//定义一个栈
int i,k;
ArcNode *p;
InitStack(&s);
int count=0;
int indegree[MaxVertexNum];
FindIndegree(G,indegree);//计算所有结点的度
printf("拓扑排序为: \n");
for(i=0;i<G.vexnum;i++)
{
if(indegree[i]==0)
{
Push(&s,i);
}
}
while(!StackEmpty(s))
{
Pop(&s,&i);
printf("%d\t",G.vertices[i].data);
count++;
for(p=G.vertices[i].firstarc;p;p=p->nextarc)//遍历邻接表
{
k=p->adjvex;
indegree[k]--;//相邻的结点入度减一
if(indegree[k]==0)//如果入度减一之后,入度为零,入栈
{
Push(&s,k);
}
}
}
if(count<G.vexnum)
{
printf(" 此图有回路,不能进行拓扑排序! \n");
return false;
}
else
{
return true;
}
}
int main()
{
ALGraph G;
CreateGraph(&G);
Display(G);
TopologicalSort(G);
return 0;
}