有向图无向图领接表深度优先广度优先最小生成树

时间:2021-11-15 12:36:00
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXVEX 100
#define MAXEDGE 100
#define INFINITY 65535
#define MAXSIZE 100

typedef int Status;	                           /* Status是函数的类型 */
typedef int VertexType;                        /* 顶点类型 */
typedef int EdgeType;                          /* 边上的权值类型 */
typedef int Boolean;
Boolean visited[MAXVEX];


typedef struct
{
	VertexType vexs[MAXVEX];                    /* 顶点表 */
	EdgeType arc[MAXVEX][MAXVEX];               /* 邻接矩阵,看作边表 */
	int numNodes, numEdges;                     /* 图中当前的顶点数和边数  */
}MGraph;

typedef struct EdgeNode                         /* 边表结点 */
{
	int adjvex;                                 /* 邻接点域,存储该顶点对应的下标 */
	int weight;		                            /* 用于存储权值,对于非网图可以不需要(手绘图) */
	struct EdgeNode *next;                      /* 链域,指向下一个邻接点 */
}EdgeNode;

typedef struct VertexNode /* 顶点表结点 */
{
	int in;	/* 顶点入度 */
	int data; /* 顶点域,存储顶点信息 */
	EdgeNode *firstedge;/* 边表头指针 */
}VertexNode, AdjList[MAXVEX];

typedef struct
{
	AdjList adjList;
	int numNodes, numEdges; /* 图中当前顶点数和边数 */
}graphAdjList,*GraphAdjList;

typedef struct      /*对边集数组Edge结构的定义*/
{
    int begin;
    int end;
    int weight;
}Edge;

typedef struct
{
	int data[MAXSIZE];
	int front;    	        /* 头指针 */
	int rear;		        /* 尾指针 */
}Queue;

Status InitQueue(Queue *Q)  /* 初始化空队列Q */
{
	Q->front=0;
	Q->rear=0;
	return  OK;
}

Status QueueEmpty(Queue Q)  /*判断队列是否为空*/
{
	if(Q.front==Q.rear)     /* 队列空的标志 */
		return TRUE;
	else
		return FALSE;
}

Status EnQueue(Queue *Q,int e)      /*队列插入操作*/
{
	if ((Q->rear+1)%MAXSIZE == Q->front)	/* 队列满的判断 */
		return ERROR;
	Q->data[Q->rear]=e;			        /* 将元素e赋给队尾 */
	Q->rear=(Q->rear+1)%MAXSIZE;        /* rear指针向后移一位置, */
                                        /* 若到最后则转到数组头部 */
	return  OK;
}

Status DeQueue(Queue *Q,int *e)     /*队列删除操作*/
{
	if (Q->front == Q->rear)			/* 队列空的判断 */
		return ERROR;
	*e=Q->data[Q->front];				/* 将队头元素赋值给e */
	Q->front=(Q->front+1)%MAXSIZE;	    /* front指针向后移一位置, */
                                        /* 若到最后则转到数组头部 */
	return  OK;
}

Status  CreateMGraph(MGraph *G)            /* 无向网图邻接矩阵表示 */
{
	int i,j,k,w;
	//char v[1000];
	printf("输入顶点数和边数:\n");
	scanf("%d%d",&G->numNodes,&G->numEdges); /* 输入顶点数和边数 */
	for(i=0;i<G->numNodes;i++)
           //scanf(&G->vexs[i]);
           G->vexs[i]=i;                    /* 建立顶点表 */
    for(i=0;i<G->numNodes;i++)
		for(j=0;j<G->numNodes;j++)
			{
			    if(i==j)
                    G->arc[i][j]=0;
                else
                G->arc[i][j]=INFINITY;
			}

			printf("对于非网图另权为1\n");	                /* 邻接矩阵初始化 */
	for(k=0;k<G->numEdges;k++)               /* 建立邻接矩阵 */
	{
		printf("输入第%d条边(vi,vj)上的下标i,下标j和权w:\n",k+1);

		scanf("%d%d%d",&i,&j,&w);
		G->arc[i][j]=w;
		G->arc[j][i]= G->arc[i][j];             /* 无向图,矩阵对称 */
	}
	PrintGraph(G);
	return OK;
}

Status CreateDGraph(MGraph *G)               /* 有向网图邻接矩阵表示 */
{
    int v1,v2,i,j,k,w;
    //char ch;
    printf("图顶点数和弧数:");             /*确定图顶点数和边数*/
    scanf("%d%d",&G->numNodes,&G->numEdges);
    //ch=getchar();
    for(i=0;i<G->numNodes;i++)                  /*定义顶点名称*/
        {
            printf("第%d个顶点:v",i+1);
            scanf("%d",&G->vexs[i]);
            //ch=getchar();
        }
    for(i=0;i<G->numNodes;i++)                  /*初始化邻接矩阵*/
        for(j=0;j<G->numNodes;j++)
       {
             if(i==j)
                G->arc[i][j]=0;
            else
                G->arc[i][j]=INFINITY;
       }
    for(k=1;k<=G->numEdges;k++)             /*带方向邻接矩阵构建*/
    {
        printf("输入第%d条边两个顶点,第一个为弧尾,第二个为弧头和权值w:\n",k);
        printf("v");
        scanf("%d",&v1);
        printf("v");
        scanf("%d",&v2);
        printf("权值w:");
        scanf("%d",&w);
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);
        //printf("%d %d",i,j);
        G->arc[i][j]=w;   /*赋权*/
     }
    PrintGraph(G);      /*打印出有向图的邻接矩阵*/
    return OK;
}

void CreateALGraph(MGraph G,GraphAdjList *G1)
{
   int i,j;
	EdgeNode *e;

	*G1 = (GraphAdjList)malloc(sizeof(graphAdjList));

	(*G1)->numNodes=G.numNodes;
	(*G1)->numEdges=G.numEdges;
	for(i= 0;i <G.numNodes;i++)                      /* 读入顶点信息,建立顶点表 */
	{
		(*G1)->adjList[i].in=0;
		(*G1)->adjList[i].data=G.vexs[i];
		(*G1)->adjList[i].firstedge=NULL; 	              /* 将边表置为空表 */
	}

	for(i=0;i<G.numNodes;i++)                         /* 建立边表 */
	{
		for(j=0;j<G.numNodes;j++)
		{
			if (G.arc[i][j]==1)
			{
				e=(EdgeNode *)malloc(sizeof(EdgeNode));
				e->adjvex=j;					            /* 邻接序号为j */
				e->next=(*G1)->adjList[i].firstedge;	    /* 将当前顶点上的指向的结点指针赋值给e */
				(*G1)->adjList[i].firstedge=e;		        /* 将当前顶点的指针指向e */
				(*G1)->adjList[j].in++;

			}
		}
	}

}

void DispGraphAdjList(GraphAdjList *G1)
{
    int i;
    EdgeNode *p;
    printf("图的邻接表表示如下\n");
    printf("%6s%6s%2s%12s\n","编号","     ","顶点","相邻边编号");
    for(i=0;i<(*G1)->numNodes;i++)
    {
        printf("%4d        v%d",i,(*G1)->adjList[i].data);//
        for(p=(*G1)->adjList[i].firstedge;p!=NULL;p=p->next)
            printf("%6d",p->adjvex);
        printf("\n");
    }
}


Status DestroyMGraph(MGraph G)         /*销毁表*/
{
    G.numEdges=NULL;
    G.numNodes=NULL;
    return OK;
}

Status LocateVex(MGraph *G,int v)      /*找出任意顶点在顶点集中的编号*/
{
    int a=0,i;
    for(i=0;i<G->numNodes;i++)
    {
        if(v==G->vexs[i])
        {
            return a;
        }
        else
            a++;
    }
    if(v>=G->numNodes)
    {
        return FALSE;
    }
}

Status PrintGraph(MGraph *G)       /*打印图*/
{
    int i,j;
    printf("图中顶点有%3d个,分别为:",G->numNodes);
    for(i=0;i<G->numNodes;i++)
        printf("v%d ",G->vexs[i]);
    printf("\n邻接矩阵关系:\n");
    for(i=0;i<G->numNodes;i++)
      {
          for(j=0;j<G->numNodes;j++)
              {
                  if(G->arc[i][j]==INFINITY)
                        printf("    ∞");
                  else
                        printf("%6d",G->arc[i][j]);
              }
            printf("\n");
      }
      return OK;
}

void DFS(MGraph G,int i)         /*邻接矩阵的深度遍历算法*/
{
    int j;
    visited[i]=TRUE;
    printf("v%d ",G.vexs[i]);
    for(j=0;j<G.numNodes;j++)
        if(G.arc[i][j]==1&&!visited[j])
        DFS(G,j);
}

void DFSTraverse(MGraph G)      /*邻接矩阵的深度优先递归算法*/
{
    int i;
    for(i=0;i<G.numNodes;i++)
        visited[i]=FALSE;
    for(i=0;i<G.numNodes;i++)
        if(!visited[i])
        DFS(G,i);
}

void DFS1(GraphAdjList G1,int i)  /*邻接表的深度遍历算法*/
{
    EdgeNode *p;
    visited[i]=TRUE;
    printf("v%d ",G1->adjList[i].data);
    p=G1->adjList[i].firstedge;
    while(p)
    {
        if(!visited[p->adjvex])
            DFS1(G1,p->adjvex);
        p=p->next;
    }
}

void DFSTraverse1(GraphAdjList G1)  /*邻接表的深度优先递归算法*/
{
    int i;
    for(i=0;i<G1->numNodes;i++)
        visited[i]=FALSE;
    for(i=0;i<G1->numNodes;i++)
        if(!visited[i])
        DFS1(G1,i);
}

void BFSTraverse(MGraph G)   /*邻接矩阵的广度遍历算法*/
{
	int i, j;
	Queue Q;   /*定义队列Q*/
	for(i=0; i< G.numNodes; i++)
       	visited[i] = FALSE;
    InitQueue(&Q);		                            /* 初始化队列 */
    for(i = 0; i < G.numNodes; i++)
    {
		if (!visited[i])	                        /* 未访问过处理 */
		{
			visited[i]=TRUE;		                /* 设置当前顶点访问过 */
			printf("v%d ", G.vexs[i]);              /* 打印顶点*/
			EnQueue(&Q,i);		                    /* 顶点入队 */
			while(!QueueEmpty(Q))	                /* 若当前队列不为空 */
			{
				DeQueue(&Q,&i);             	    /* 将队对元素出队列,赋值给i */
				for(j=0;j<G.numNodes;j++)
				{

					if(G.arc[i][j] == 1 && !visited[j]) /* 判断其它顶点若与当前顶点存在边且未访问过  */
					{
 						visited[j]=TRUE;			/* 将找到的此顶点标记为已访问 */
						printf("v%d ", G.vexs[j]);	/* 打印顶点 */
						EnQueue(&Q,j);				/* 将找到的此顶点入队列  */
					}
				}
			}
		}
	}
}

void BFSTraverse1(GraphAdjList G1)          /*邻接表的广度遍历算法*/
{
    int i;
    EdgeNode *p;
	Queue Q;
	for(i = 0; i < G1->numNodes; i++)
       	visited[i] = FALSE;
    InitQueue(&Q);
   	for(i = 0; i < G1->numNodes; i++)
   	{
		if (!visited[i])
		{
			visited[i]=TRUE;
			printf("v%d ",G1->adjList[i].data);/* 打印顶点 */
			EnQueue(&Q,i);
			while(!QueueEmpty(Q))
			{
				DeQueue(&Q,&i);
				p = G1->adjList[i].firstedge;	/* 找到当前顶点的边表链表头指针 */
				while(p)
				{
					if(!visited[p->adjvex])	/* 若此顶点未被访问 */
 					{
 						visited[p->adjvex]=TRUE;
						printf("v%d ",G1->adjList[p->adjvex].data);
						EnQueue(&Q,p->adjvex);	/* 将此顶点入队列 */
					}
					p = p->next;	/* 指针指向下一个邻接点 */
				}
			}
		}
	}
}

void MiniSpanTree_Prim(MGraph *G)/* Prim算法生成最小生成树  */
{
	int min, i, j, k;
	int adjvex[MAXVEX];		                /* 保存相关顶点下标 */
	int lowcost[MAXVEX];	                /* 保存相关顶点间边的权值 */
	lowcost[0] = 0;                         /* 初始化第一个权值为0,即v0加入生成树 */
                            /* lowcost的值为0,在这里就是此下标的顶点已经加入生成树 */
	adjvex[0] = 0;			                /* 初始化第一个顶点下标为0 */
	for(i = 1; i < G->numNodes; i++)	    /* 循环除下标为0外的全部顶点 */
	{
		lowcost[i] = G->arc[0][i];	        /* 将v0顶点与之有边的权值存入数组 */
		adjvex[i] = 0;					    /* 初始化都为v0的下标 */
	}
	for(i = 1; i < G->numNodes; i++)
	{
		min = INFINITY;	                    /* 初始化最小权值为∞, */
                                        /* 通常设置为不可能的大数字如32767、65535等 */
		j = 1;
		k = 0;
		while(j < G->numNodes)	            /* 循环全部顶点 */
		{
			if(lowcost[j]!=0 && lowcost[j] < min)/* 如果权值不为0且权值小于min */
			{
				min = lowcost[j];	    /* 则让当前权值成为最小值 */
				k = j;			        /* 将当前最小值的下标存入k */
			}
			j++;
		}
		printf("(%d, %d)\n", adjvex[k], k);/* 打印当前顶点边中权值最小的边 */
		lowcost[k] = 0;                 /* 将当前顶点的权值设置为0,表示此顶点已经完成任务 */
		for(j = 1; j < G->numNodes; j++)	/* 循环所有顶点 */
		{
			if(lowcost[j]!=0 && G->arc[k][j] < lowcost[j])
			{               /* 如果下标为k顶点各边权值小于此前这些顶点未被加入生成树权值 */
				lowcost[j] = G->arc[k][j];/* 将较小的权值存入lowcost相应位置 */
				adjvex[j] = k;				/* 将下标为k的顶点存入adjvex */
			}
		}
	}
}

void Swapn(Edge *edges,int i, int j)/* 交换权值 以及头和尾 */
{
	int temp;
	temp = edges[i].begin;
	edges[i].begin = edges[j].begin;
	edges[j].begin = temp;
	temp = edges[i].end;
	edges[i].end = edges[j].end;
	edges[j].end = temp;
	temp = edges[i].weight;
	edges[i].weight = edges[j].weight;

	edges[j].weight = temp;
}

void sort(Edge edges[],MGraph *G)/* 对权值进行排序 */
{
	int i, j;
	for ( i = 0; i < G->numEdges; i++)
	{
		for ( j = i + 1; j < G->numEdges; j++)
		{
			if (edges[i].weight > edges[j].weight)
			{
				Swapn(edges, i, j);
			}
		}
	}
	printf("权排序之后的为:\n");
	for (i = 0; i < G->numEdges; i++)
	{
		printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
	}

}

int Find(int *parent, int f)/* 查找连线顶点的尾部下标 */
{
	while ( parent[f] > 0)
	{
		f = parent[f];
	}
	return f;
}


void MiniSpanTree_Kruskal(MGraph G)/* 生成最小生成树 */
{
	int i, j, n, m;
	int k = 0;
	int parent[MAXVEX];/* 定义一数组用来判断边与边是否形成环路 */

	Edge edges[MAXEDGE];/* 定义边集数组,edge的结构为begin,end,weight,均为整型 */


	for ( i = 0; i < G.numNodes-1; i++)/* 用来构建边集数组并排序*/
	{
		for (j = i + 1; j < G.numNodes; j++)
		{
			if (G.arc[i][j]<INFINITY)
			{
				edges[k].begin = i;
				edges[k].end = j;
				edges[k].weight = G.arc[i][j];
				k++;
			}
		}
	}
	sort(edges, &G);
	for (i = 0; i < G.numNodes; i++)
		parent[i] = 0;                  /* 初始化数组值为0 */

	printf("打印最小生成树:\n");
	for (i = 0; i < G.numEdges; i++)	/* 循环每一条边 */
	{
		n = Find(parent,edges[i].begin);
		m = Find(parent,edges[i].end);
		if (n != m)             /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */
		{
			parent[n] = m;	    /* 将此边的结尾顶点放入下标为起点的parent中。 */
                                /* 表示此顶点已经在生成树集合中 */
			printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
		}
	}
}

int main()
{
	int a,u,m,end_loop=0;
	char value;
	MGraph G;
	GraphAdjList G1;
	printf("*******************************************************************\n");
	printf("************-> case 0:结束循环退出                 ****************\n");
	printf("************-> case 1:定义构造图(邻接矩阵)无向图 ****************\n");
	printf("************-> case 2:定义构造图(邻接矩阵)有向图 ****************\n");
	printf("************-> case 3:定义构造图(邻接表)          ****************\n");
	printf("************-> case 4:销毁图                       ****************\n");
	printf("************-> case 5:查找顶点集vex[i]中一点的标号 ****************\n");
	printf("************-> case 6:输出当前图(邻接矩阵)        ****************\n");
	printf("************-> case 7:邻接矩阵的DFS深度优先遍历    ****************\n");
	printf("************-> case 8:邻接表的DFS深度优先遍历      ****************\n");
	printf("************-> case 9:邻接矩阵的BFS广度优先遍历    ****************\n");
	printf("************-> case 10:邻接表的BFS广度优先遍历     ****************\n");
	printf("************-> case 11:prim算法求最小生成树        ****************\n");
	printf("************-> case 12:kruskal算法求最小生成树     ****************\n");
	printf("************-> case 13:邻接表建表生成              ****************\n");
	printf("*******************************************************************\n");
	while(scanf("%d",&a)!=EOF)
	{
	  switch(a)
	{
	    case 0:end_loop=1;break;
	    case 1:{
                CreateMGraph(&G);
                printf("************-> case 4:销毁图                       ****************\n");
                printf("************-> case 6:输出当前图(邻接矩阵)        ****************\n");
                printf("************-> case 7:邻接矩阵的DFS深度优先遍历    ****************\n");
                printf("************-> case 9:邻接矩阵的BFS广度优先遍历    ****************\n");
                printf("************-> case 11:prim算法求最小生成树        ****************\n");
                printf("************-> case 12:kruskal算法求最小生成树     ****************\n");
                break;
                }
	    case 2:CreateDGraph(&G);break;
	    case 3:{
                    CreateMGraph(&G);      /*以邻接矩阵读入数据后生成邻接表*/
                    CreateALGraph(G,&G1);
                    DispGraphAdjList(&G1);
                    printf("************-> case 4:销毁图                       ****************\n");
                    printf("************-> case 8:邻接表的DFS深度优先遍历      ****************\n");
                    printf("************-> case 10:邻接表的BFS广度优先遍历     ****************\n");
                    printf("************-> case 13:邻接表建表生成              ****************\n");
                    break;
	    }
	    case 4:{
                            DestroyMGraph(G);
                            printf("图已销毁!\n");
                            printf("\n");
                            break;
                }
	    case 5:{
                    printf("输入要查找的顶点:v");
                    scanf("%d",&u);
                    m=LocateVex(&G,u);
                    if(m==-1)
                        printf("出错!\n");
                    else
                        printf("查找顶点的数组编号为:%d\n",m);
                    break;
                }
        case 6:PrintGraph(&G);printf("\n");break;
        case 7:DFSTraverse(G);printf("\n");break;
        case 8:DFSTraverse1(G1);printf("\n");break;
        case 9:BFSTraverse(G);printf("\n");break;
        case 10:BFSTraverse1(G1);printf("\n");break;
        case 11:MiniSpanTree_Prim(&G);printf("\n");break;
        case 12:MiniSpanTree_Kruskal(G);printf("\n");break;
        case 13:DispGraphAdjList(&G1);printf("\n");break;
	}
    if(end_loop==1)
        break;
	}
	return 0;
}