数据结构 (图)

数据结构(图)

图的创建,遍历,AOV网创建

采用C语言,以便熟练stack栈的底层实现

AOV网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的图(Activity On Vertex Network),简称AOV网。

拓扑排序:将AOV网中所有的顶点排成一个线性序列,该序列满足:若在该AOV网中由顶点Vi到顶点Vj有一条路径,则在改线性序列中的顶点Vi必定在顶点Vj之前。简而言之,AOV网解决的是先后顺序问题。是求关键路径的基础。

#include 
#include 
#pragma warning( disable : 4996 )

#define  MAX_VERTEX_NUM 20//最大顶点个数
#define  VertexType int//顶点数据的类型
const int MAXV=100;//最多边数
#define DATA1 "D:\\test.txt"//顶点储存位置
#define DATA2 "D:\\testplus.txt"//边储存位置

FILE *fp;

typedef struct ArcNode{
    int adjvex;//邻接点在数组中的位置下标
    struct ArcNode * nextarc;//指向下一个邻接点的指针
}ArcNode;

typedef struct VNode{
    VertexType data;//顶点的数据域
    ArcNode * firstarc;//指向邻接点的指针
}VNode,AdjList[MAX_VERTEX_NUM];//存储各链表头结点的数组

typedef struct {
    AdjList vertices;//图中顶点及各邻接点数组
    int vexnum,arcnum;//记录图中顶点数和边或弧数
}ALGraph;

//找到顶点对应在邻接表数组中的位置下标
int LocateVex(ALGraph G,VertexType u){
    for (int i=0; i<G.vexnum; i++) {
        if (G.vertices[i].data==u) {
            return i;
        }
    }
    return -1;
}

//创建AOV网,构建邻接表
void CreateAOV(ALGraph **G){//可将输入数据写入文件
	fp=fopen(DATA1,"w");
    *G=(ALGraph*)malloc(sizeof(ALGraph));
    printf("请输入活动数,边数(用,隔开)\n");
    scanf("%d,%d",&((*G)->vexnum),&((*G)->arcnum));
    for (int i=0; i<(*G)->vexnum; i++) {
		printf("请输入活动\n");
        scanf("%d",&((*G)->vertices[i].data));
		fprintf(fp,"%d\n",(*G)->vertices[i].data);
        (*G)->vertices[i].firstarc=NULL;
    }
	fclose(fp);
    VertexType initial,end;
	fp=fopen(DATA2,"w");
    for (int i=0; i<(*G)->arcnum; i++) {
		printf("请输入弧(活动优先顺序“,”隔开)\n");
        scanf("%d,%d",&initial,&end);
        fprintf(fp,"%d,%d\n",initial,end);
        ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex=LocateVex(*(*G), end);
        p->nextarc=NULL;
       
        int locate=LocateVex(*(*G), initial);
        p->nextarc=(*G)->vertices[locate].firstarc;
        (*G)->vertices[locate].firstarc=p;
    }
	fclose(fp);
}

void ReadAOV(ALGraph **G){
    *G=(ALGraph*)malloc(sizeof(ALGraph));
    //printf("请输入活动数,边数(用,隔开)\n");
    //scanf("%d,%d",&((*G)->vexnum),&((*G)->arcnum));
	(*G)->vexnum=MAX_VERTEX_NUM;
	(*G)->arcnum=MAXV;
		fp=fopen(DATA1,"r");
    for (int i=0; i<(*G)->vexnum; i++) {
		fscanf(fp,"%d",&(*G)->vertices[i].data);
        (*G)->vertices[i].firstarc=NULL;
		if (feof(fp)) 
			{
				(*G)->vexnum=i;
				break;
		    }
    }
	fclose(fp);
    VertexType initial,end;
	fp=fopen(DATA2,"r");
    for (int i=0; i<(*G)->arcnum; i++) {
        fscanf(fp,"%d,%d",&initial,&end);       
        ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex=LocateVex(*(*G), end);
        p->nextarc=NULL;
       
        int locate=LocateVex(*(*G), initial);
        p->nextarc=(*G)->vertices[locate].firstarc;
        (*G)->vertices[locate].firstarc=p;
		if (feof(fp)) 
			{
				(*G)->arcnum=i;
				break;
		    }
    }
	fclose(fp);
}
//结构体定义栈结构
typedef struct stack{
    VertexType data;
    struct stack * next;
}stack;
//初始化栈结构
void initStack(stack* *S){
    (*S)=(stack*)malloc(sizeof(stack));
    (*S)->next=NULL;
}
//判断链表是否为空
bool StackEmpty(stack S){
    if (S.next==NULL) {
        return true;
    }
    return false;
}
//进栈,以头插法将新结点插入到链表中
void push(stack *S,VertexType u){
    stack *p=(stack*)malloc(sizeof(stack));
    p->data=u;
    p->next=NULL;
    p->next=S->next;
    S->next=p;
}
//弹栈函数,删除链表首元结点的同时,释放该空间,并将该结点中的数据域通过地址传值给变量i;
void pop(stack *S,VertexType *i){
    stack *p=S->next;
    *i=p->data;
    S->next=S->next->next;
    free(p);
}
//统计各顶点的入度
void FindInDegree(ALGraph G,int indegree[]){
    //初始化数组,默认初始值全部为0
    for (int i=0; i<G.vexnum; i++) {
        indegree[i]=0;
    }
    //遍历邻接表,根据各链表中结点的数据域存储的各顶点位置下标,在indegree数组相应位置+1
    for (int i=0; i<G.vexnum; i++) {
        ArcNode *p=G.vertices[i].firstarc;
        while (p) {
            indegree[p->adjvex]++;
            p=p->nextarc;
        }
    }
}
void TopologicalSort(ALGraph G){
    int indegree[MAXV];//创建记录各顶点入度的数组
    FindInDegree(G,indegree);//统计各顶点的入度
    //建立栈结构,程序中使用的是链表
    stack *S;
    initStack(&S);
    //查找度为0的顶点,作为起始点
    for (int i=0; i<G.vexnum; i++) {
        if (!indegree[i]) {
            push(S, i);
        }
    }
    int count=0;
    //当栈为空,说明排序完成
    while (!StackEmpty(*S)) {
        int index;
        //弹栈,并记录栈中保存的顶点所在邻接表数组中的位置
        pop(S,&index);
        printf("%d  ",G.vertices[index].data);
        ++count;
        //依次查找跟该顶点相链接的顶点,如果初始入度为1,当删除前一个顶点后,该顶点入度为0
        for (ArcNode *p=G.vertices[index].firstarc; p; p=p->nextarc) {
            VertexType k=p->adjvex;
            if (!(--indegree[k])) {
                //顶点入度为0,入栈
                push(S, k);
            }
        }
    }
    //如果count值小于顶点数量,表明该有向图有环
    if (count<G.vexnum)  printf("该图有回路\n");
	else printf("该图无回路\n");
}
int main()
{
	ALGraph *G;
	int choice;
	while(true)
	{
		printf("    拓扑排序实例coding \n");
		printf("**********主菜单**********\n");
		printf("     (1)重新创建图\n"); 
		printf("     (2)读取现有图\n"); 
		printf("     (3)拓扑排序\n"); 		
		printf("     (0)退出\n"); 
		printf("请选择(1,2,3,0):\n");
		scanf("%d",&choice);
		if(choice<0||choice>3)
			continue;
		switch(choice)
		{		
			case 1:				
				CreateAOV(&G);//创建AOV网
				break;
			case 2:
				ReadAOV(&G);//读取AOV网		
				break;
			case 3:
				TopologicalSort(*G);//进行拓扑排序
				break; 			
			case 0:
				exit(0);
			default:
				break;
		}
	}
	system("pause");
    return  0;
}

用于测试的有向图:(12个活动,16条边)

数据结构 (图)_第1张图片

运行效果显示:
数据结构 (图)_第2张图片

你可能感兴趣的:(数据结构,C)