第七章-图(6)有向无环图及其应用-拓扑排序

1、有向无环图:无环的有向图



有向无环图是描述含有公共子式的表达式的有效工具。

例如下述表达式  ((a+b)*(b*(c+d))+(c+d)*e)*((c+d)*e)

可以用第六章讨论的二叉树表示:如图7.22所示

仔细观察该表达式,可发现有一些相同的子表达式,如(c+d)和(c+d)*e等,在二叉树中,它们也重复出现。若利用有向无环图,则可实现对相同子式的共享,从而节省存储空间。例如图 7.23 所示为表示同一表达式的有向无环图。



2、拓扑排序:

由某个集合上的一个偏序得到该集合上的一个全序。

扫描二维码关注公众号,回复: 2162165 查看本文章



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);
}


猜你喜欢

转载自blog.csdn.net/qq_40191710/article/details/79579698