1、有向无环图:无环的有向图
有向无环图是描述含有公共子式的表达式的有效工具。
例如下述表达式 ((a+b)*(b*(c+d))+(c+d)*e)*((c+d)*e)
可以用第六章讨论的二叉树表示:如图7.22所示
仔细观察该表达式,可发现有一些相同的子表达式,如(c+d)和(c+d)*e等,在二叉树中,它们也重复出现。若利用有向无环图,则可实现对相同子式的共享,从而节省存储空间。例如图 7.23 所示为表示同一表达式的有向无环图。
2、拓扑排序:
由某个集合上的一个偏序得到该集合上的一个全序。
3、如何进行拓扑排序:
(1)在有向图中选一个没有前驱的顶点且输出之。
(2)从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。
后一种情况则说明有向图中存在环。
它的拓扑排序的有序序列为:
--------------------------------------------------------------------------------------------------------------------------------
代码:
//拓扑排序的有向图
//以邻接表的形式存储
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#define ERROR 0
#define OK 1
#define INFINITY INT_MAX //最大值
#define MAX_VERTEX_NUM 21 //最大顶点个数
#define STACK_INT_SIZE 100 //
#define STACKINCREAMENT 10 //
int indegree[MAX_VERTEX_NUM]; //求最小生成树中的辅助数组
typedef enum{ DG,DN,UDG,UDN } GraphKind; //{有向图,有向网,无向图,无向网}
//--------图的邻接表存储表示---------------//
typedef struct ArcNode{
int adjvex; //该弧所指向的顶点的位置
int quan;
struct ArcNode *nextarc; //指向下一条弧的指针
}ArcNode,*AList; //表结点
typedef struct VNode{
char data; //顶点信息
AList firstarc; //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM]; //头结点
typedef struct{
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和弧数
GraphKind kind; //图的种类标志
}ALGraph;
//------------------------------------------------//
//----------------------------------------//
//----------栈的操作-------
typedef struct{
int *base;
int *top;
int stacksize;
}SqStack; //栈
//创建栈
int InitStack(SqStack &S){
S.base=(int *)malloc(STACK_INT_SIZE*sizeof(int));
if(!S.base) return ERROR;
S.top=S.base;
S.stacksize=STACK_INT_SIZE;
return OK;
}
//元素入栈
int Push(SqStack &S,int e){
if(S.top-S.base>=S.stacksize){
S.base=(int *)realloc(S.base,(S.stacksize+STACKINCREAMENT)*sizeof(int));
if(!S.base)
return ERROR;
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREAMENT;
}
*S.top++=e;
return OK;
}
//元素出栈
int Pop(SqStack &S,int &e){
if(S.top==S.base) return ERROR;
e=*--S.top;
return OK;
}
//判断栈是否为空
int StackEmpty(SqStack S){
if(S.top==S.base)
return OK;
return ERROR;
}
//邻接表顶点定位
int LocateVex(ALGraph G,char v){
int m;
for(m=1;m<=G.vexnum;m++){
if(G.vertices[m].data==v)
return m;
}
printf("你输入的顶点不存储!");
return ERROR;
}
//创建邻接表
int CreatAList(ALGraph &G){
int i,j,m,n,key[MAX_VERTEX_NUM];
char x,y;
AList p,q;
printf("邻接表,请输入顶点的个数和弧个数:"); //初始化邻接表
scanf("%d %d",&G.vexnum,&G.arcnum);
if(G.vexnum>20){ //顶点个数过多
printf("你输入的顶点个数超过最大值");
return ERROR;
}
printf("请输入 %d 个顶点数:\n",G.vexnum);
for(i=1;i<=G.vexnum;i++){
fflush(stdin);
scanf("%c",&G.vertices[i].data); //构造顶点向量的值
G.vertices[i].firstarc=NULL; //指向下一条弧的指针 先初始化为 NULL
key[i]=0; //
}
printf("请输入弧(如 A B ,其中 AB 与 BA是不同的弧):");
for(j=1;j<=G.arcnum;j++){ //输入弧
fflush(stdin);
scanf("%c %c",&x,&y);
m=LocateVex(G,x); //定位
n=LocateVex(G,y);
p=G.vertices[m].firstarc; // AList p,q
q=(AList)malloc(sizeof(ArcNode));
if(!q) return ERROR;
q->nextarc=NULL; //q初始化的过程
q->adjvex=n;
while(key[m] && p->nextarc){
p=p->nextarc;
key[m]++;
}
if(!key[m]){ //key[m]为0
G.vertices[m].firstarc=q;
key[m]++;
}
else
p->nextarc=q;
}
return OK;
}
int PrintAList(ALGraph &G2){
int i,j;
AList s;
printf("有向图的邻接表: \n");
for(i=1;i<=G2.vexnum;i++){ //将邻接表输出
printf("%c",G2.vertices[i]);
s=G2.vertices[i].firstarc;
while(s){
j=s->adjvex; //该顶点在数组中的位置
fflush(stdin);
printf("<%c",G2.vertices[i]);
printf(",%c>",G2.vertices[j]);
s=s->nextarc;
}
printf("\n");
}
return OK;
}
//计算各定点入度
void FindInDegree(ALGraph G,int in[]){
int i,j,k;
AList p;
for(k=1;k<=G.vexnum;k++)
in[k]=0;
for(i=1;i<=G.vexnum;i++){
p=G.vertices[i].firstarc;
while(p){
j=p->adjvex;
in[j]++;
p=p->nextarc;
}
}
}
//有向图的拓扑排序
int TopologicalSort(ALGraph G){
int i,k,count;
AList p;
SqStack S;
FindInDegree(G,indegree); //对各定点求入度
InitStack(S);
for(i=1;i<=G.vexnum;i++){ //建 0 入度定点栈 S
if(!indegree[i])
Push(S,i); //入度为 0 者入栈
}
count=0; //对输出顶点计数
if(StackEmpty(S))
printf("此图不符合条件!");
while(!StackEmpty(S)){
Pop(S,i);
printf("%c ",G.vertices[i].data);
count++; //输出 i 号顶点并计数
for(p=G.vertices[i].firstarc ; p ; p=p->nextarc){
k=p->adjvex; //对 i 号顶点的每个临界点的入度减 1
if(!(--indegree[k]))
Push(S,k); //若入度减为 0 ,则入栈
}
}
if(count<=G.vexnum)
return ERROR;
else
return OK;
return OK;
}
void main(){
ALGraph G;
CreatAList(G);
PrintAList(G);
printf("有向图的拓扑排序:\n");
TopologicalSort(G);
}