拓扑排序一问题描述本次课程设计题目是:编写函数实现图的拓扑排序二概要设计1.算法中用到的所有各种数据类型的定义在该程序中用邻接表作为图的存储结构。
首先,定义表结点和头结点的结构类型,然后定义图的结构类型。
创建图用邻接表存储的函数,其中根据要求输入图的顶点和边数,并根据要求设定每条边的起始位置,构建邻接表依次将顶点插入到邻接表中。
拓扑排序的函数在该函数中首先要对各顶点求入度,其中要用到求入度的函数,为了避免重复检测入度为零的顶点,设置一个辅助栈,因此要定义顺序栈类型,以及栈的函数:入栈,出栈,判断栈是否为空。
2.各程序模块之间的层次调用关系第一部分,void CreatGraph(ALGraph *G)函数构建图,用邻接表存储。
这个函数没有调用函数。
第二部分,void TopologicalSort(ALGraph *G)输出拓扑排序函数,这个函数首先调用FindInDegree(G,indegree)对各顶点求入度indegree[0……vernum-1];然后设置了一个辅助栈,调用InitStack(&S)初始化栈,在调用Push(&S,i)入度为0者进栈,while(!StackEmpty(&S))栈不为空时,调用Pop(&sS,&n)输出栈中顶点并将以该顶点为起点的边删除,入度indegree[k]--,当输出某一入度为0的顶点时,便将它从栈中删除。
第三部分,主函数,先后调用void CreatGraph(ALGraph *G)函数构建图、void TopologicalSort(ALGraph *G)函数输出拓扑排序实现整个程序。
3.设计的主程序流程三详细设计1.实现概要设计中定义的所有数据类型#include<stdio.h>#include<stdlib.h>#include <malloc.h>#define MAX_VEXTEX_NUM 20 //*定义点最大的数值为顶30*// #define M 20#define STACK_INIT_SIZE 100 //*定义点最大的数值为顶30*//#define STACKINCREMENT 10 //*定义栈的增量为10*//#define OK 1#define ERROR 0typedef char ElemType; //*定义栈顶元素类型*//typedef struct ArcNode{int adjvex; //该弧所指向的顶点的位置//struct ArcNode *nextarc; //指向下一条弧的指针//}ArcNode; //*表结点*//typedef struct VNode{char data; //顶点信息ArcNode *firstarc; //指向第一条依附该顶点的弧的指针// }VNode,AdjList[MAX_VEXTEX_NUM];typedef struct{AdjList vertices;int vexnum, arcnum; //图的当前顶点数和弧数//}ALGraph;typedef struct //构建栈//{ElemType *base;//*在栈构造之前的指针*//ElemType *top;//*栈顶指针*//int stacksize;//*定义所分配的存储空间*//}SqStack;//*顺序栈*//2.算法和各模块的代码程序中各函数算法思想如下:○1void InitStack(SqStack *S)初始化栈将栈的空间设为STACK-INIT-SIZE。
○2int Pop(SqStack *S,ElemType *e)出栈操作,若站不空,删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR。
○3void Push(SqStack *S,ElemType e)进栈操作,插入元素e为新的栈顶元素。
○4int StackEmpty(SqStack *S)判断栈是否为空,语句if (S->top=S->base )判断,若栈不为空,则删除S的栈顶元素,并返回OK;否则返回ERROR。
○5void CreatGraph (ALGraph *G)构建图,用邻接表存储,首先定义邻接表指针变量,输入顶点数和弧数,初始化邻接表,将表头向量域置空,输入存在弧的点集合,当输入顶点值超出输入值的范围就会出错,否则依次插入进邻接表,最后输出建立好的邻接表。
○6void FindInDegree(ALGrap G, int indegreee[])求入度操作,设一个存放各顶点入度的数组indegreee[],然后indegreee[i]=0赋初值,for循环indegreee[]++,存储入度数。
○7void TopologicalISort(ALGraph G)输出拓扑排序函数。
其思路是若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR。
首先由于邻接表的存储结构入度为零的顶点即为没有前驱的顶点,我们可以附设一个存放个顶点入度的数组,调用FindInDegree( G, indegreee[])对各顶点求入度;为了避免重复检测入度为零0的顶点,设置一个栈,调用InitStack(&S)初始化栈,在调用Push(&S,i)入度为0者进栈,while(!StackEmpty(&S))栈不为空时,调用Pop(&sS,&n)输出栈中顶点并将以该顶点为起点的边删除,入度indegree[k]--,当输出某一入度为0的顶点时,便将它从栈中删除。
3.算法的时间复杂度和空间复杂度拓扑排序实际是对邻接表表示的图G进行遍历的过程,每次访问一个入度为零的顶点,若图G中没有回路,则需扫描邻接表中的所有边结点,在算法开始时,为建立入度数组D需访问表头向量中的所有边结点,算法的时间复杂度为O(n+e)。
四调试分析对如下有向无环图进行拓扑排序。
输入:结果如下:五心得体会在进行拓扑排序的课程设计中,更好的认识了拓扑排序。
在设计中,我们遇到了程序正确,却对某些无向图无法进行拓扑排序的问题。
多次对程序进行修改后,才可以进行拓扑排序。
问题出在调用函数的错误理解,模块之间的联系模糊不清,在同学的帮助和自己的努力思考下,我最终把这些问题一一解决,并把教训牢记在心,努力使自己得到更大的收获和提高。
因为在理论学习中没有好好的掌握,现在要独立完成一个较复杂的程序编写,确实有困难。
今后我必需扎实基础理论、认真思考,而且要践行我的承诺,一步一个脚印的走下去,才可以达到我们预期的彼岸!六程序清单#include<stdio.h>#include<stdlib.h>#include <malloc.h>#define MAX_VEXTEX_NUM 20 //*定义点最大的数值为顶30*// #define M 20#define STACK_INIT_SIZE 100 //*定义点最大的数值为顶30*//#define STACKINCREMENT 10 //*定义栈的增量为10*//#define OK 1#define ERROR 0typedef char ElemType; //*定义栈顶元素类型*//typedef struct ArcNode{int adjvex; //*该弧所指向的顶点的位置*//struct ArcNode *nextarc; //*指向下一条弧的指针*//}ArcNode; //*表结点*//typedef struct VNode{char data; //*顶点信息*//ArcNode *firstarc; //*指向第一条依附该顶点的弧的指针*// }VNode,AdjList[MAX_VEXTEX_NUM];typedef struct{AdjList vertices;int vexnum, arcnum; //*图的当前顶点数和弧数*//}ALGraph;typedef struct //*构建栈*//{ElemType *base;//*在栈构造之前的指针*//ElemType *top;//*栈顶指针*//int stacksize;//*定义所分配的存储空间*//}SqStack;//*顺序栈*//void InitStack(SqStack *); //*函数声明*//int Pop(SqStack *, ElemType &);void Push(SqStack *,ElemType );int StackEmpty(SqStack *);void CreatGraph(ALGraph *);void FindInDegree(ALGraph , int * );void TopologicalSort(ALGraph );void InitStack(SqStack *S) //*初始化栈*//{S->base=(ElemType *)malloc(STACK_INIT_SIZE*sizeof(ElemType)); //*申请新的结点并由s->base指向*//if(!S->base) //*存储分配失败*//{printf("memory allocation failed, goodbye");exit(1);}S->top=S->base; //*空栈之前的指针赋给头指针*//S->stacksize=STACK_INIT_SIZE; //*栈的空间设为Stack_init_size*//}int Pop(SqStack *S,ElemType &e) //*出栈操作*//{if(S->top==S->base) //*栈空返回OK*//{return ERROR; //*删除S的栈顶元素*//}e=*--S->top;return 0;}void Push(SqStack *S,ElemType e) //*进栈操作,插入元素e为新的栈顶元素*//{if(S->top-S->base>=S->stacksize){S->base=(ElemType*)realloc(S->base,(S->stacksize+STACKINCREMENT)*sizeof( ElemType));if(!S->base) //*存储分配失败*//{printf("memory allocation failed, goodbye");exit(1);}S->top = S->base+S->stacksize;S->stacksize+=STACKINCREMENT;}*S->top++=e;}int StackEmpty(SqStack *S) //*判断栈是否为空*//{if(S->top==S->base) //*栈不为空,则删除S的栈顶元素,并返回OK;否则返回*// return OK;elsereturn ERROR;}int locatevex(ALGraph G,char u) //*若G图中存在顶点u,则返回该顶点在图中的位置;否则返回-2.*//{int i;for(i=0;i<G.vexnum;i++){if(G.vertices[i].data==u){return i;exit(OK);}}return -2;}void CreatGraph(ALGraph *G) //*构建图建立有向的图的邻接表*// {int i,k;printf("输入结点的个数和弧数(用空格隔开):\n");scanf("%d %d",&G->vexnum,&G->arcnum);printf("输入顶点的值(用空格隔开):\n");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++){char v1,v2;int i,j;loop: printf("输入一条弧的起点和终点(用空格隔开):\n");scanf("%s %s",&v1,&v2);i=locatevex(*G,v1); //*确定v1,v2在G中的位置*// j=locatevex(*G,v2);if(i==-2||j==-2){printf("输入有误!");break; goto loop;}ArcNode *p;p = (ArcNode*)malloc(sizeof(ArcNode));if (p == NULL){printf("memory allocation failed,goodbey");exit(1);}p->adjvex=j; //*对弧结点赋值*//p->nextarc=G->vertices[i].firstarc;G->vertices[i].firstarc=p; //*插入到表头向量后面*//}ArcNode *p; //*定义邻接表指针变量*//p = (ArcNode*)malloc(sizeof(ArcNode));if (p == NULL){printf("memory allocation failed,goodbey");exit(1);}printf("建立的邻接表为:\n"); //*输出建立好的邻接表*// for(i = 0; i < G->vexnum; i++){printf("%c",G->vertices[i].data);for(p = G->vertices[i].firstarc; p; p = p->nextarc)printf("%3d",p->adjvex);printf("\n");}}void FindInDegree(ALGraph G, int indegree[]) //*求入度操作*//{int i;for (i = 0; i < G.vexnum; i++)indegree[i] = 0;for (i = 0; i < G.vexnum; i++){while (G.vertices[i].firstarc){indegree[G.vertices[i].firstarc->adjvex]++;G.vertices[i].firstarc = G.vertices[i].firstarc->nextarc;}}}void TopologicalSort(ALGraph G) //*输出拓扑排序函数。