普里姆算法与克鲁斯卡尔算法之最小生成树

#include
#include
#define MAX 1000
#define MAXLEN 20
#define MAX_ARC_NUM 100
/*---邻接矩阵---*/
typedef char VertexType;  //定义顶点类型 
typedef int WeightType;
typedef struct Graph
{
	VertexType vexs[MAXLEN]; //顶点表 
	int arc[MAXLEN][MAXLEN]; //邻接矩阵 
	int vexnum, arcnum;    //顶点数量和边数量 
}MGraph;
typedef struct Node { // 弧的定义
	VertexType head,tail;    
	// 边的两个端点下标。
	WeightType  weight ;
	// 该弧相关信息的指针
} EdgeNode;
typedef struct { // 图的定义
	VertexType vexs[MAXLEN];     
	// 顶点信息
	EdgeNode    edgelist[MAX_ARC_NUM];
	// 边集信息                     
	int    vexnum, arcnum;   // 顶点数,弧数      
} EGraph;

/*---查询顶点的下标---*/
int locate(MGraph G, VertexType ch)
{
	int i = 0;
	while (G.vexs[i] != ch)
		i++;
	return i;  	
} 
int locate(EGraph G, VertexType ch)
{
	int i = 0;
	while (G.vexs[i] != ch)
		i++;
	return i;  	
}
/*---构建图---*/
void CreateMGraph(MGraph &G)
{
	int i,j,k;
	int weight ; 
	VertexType v1;
	VertexType v2; 
	printf("\n\n请输入无向网G的顶点数和边数(用逗号隔开) : ");
	scanf("%d,%d",&G.vexnum,&G.arcnum);
	fflush(stdin);
	//建立顶点数组 
	for(i=0;i<G.vexnum;i++)
	{
		printf("请输入第%d个顶点的值(以字符型表示) : ",i+1);
		scanf("%c",&G.vexs[i]);
		fflush(stdin);
	}
	//初始化邻接矩阵 
	for (i=0; i<G.vexnum; i++) 
		for (j=0; j<G.vexnum; j++)
		{
			if(i == j)	G.arc[i][j] = 0;
			else 
				G.arc[i][j] = MAX;
		}
		k=0;
		while (k<G.arcnum) //k为顶点数 
		{
			printf("\n请输入第%d条边的信息(head,tail,weight):",k+1);
			fflush(stdin);
			scanf("%c,%c,%d", &v1,&v2,&weight);
			i = locate(G,v1); // 得出输入字符的序号,然后在邻接矩阵输入相应信息 
			j = locate(G,v2);
			G.arc[i][j] = weight; 
			G.arc[j][i] = G.arc[i][j]; 
			k++;
		}

}
void PrintMGraph(MGraph G)
{
	int i,j;
	printf("当前图的存储MGraph如下:\n");
	printf("\n当前图的顶点集G.vexs为:\n");
	printf("\n============================================\n");
	for (i=0; i<G.vexnum; i++)
		printf("  %c\t", G.vexs[i]);
	printf("\n============================================\n");
	printf("\n当前图的邻接矩阵G.arcs为:\n");
	for (i=0; i<G.vexnum; i++)
	{
		printf("\n");
		for (j=0; j<G.vexnum; j++)
		{
			if(G.arc[i][j]<MAX)
				printf(" %d\t", G.arc[i][j]);
			else
				printf(" %c\t",'M');
		}
	}
}
void MiniSpanTree_Prim(MGraph G, VertexType ch)
{
	int i, k,j;
	struct
	{
		VertexType adjvex;  //存放lowcost相应单元权值对应的顶点的下标,用来说明这个权值是这个下标对应顶点的其中一条边上的 
		int lowcost; //权值 
	}closedge[MAXLEN];

	k = locate(G, ch); //这里以ch为起始点,k是ch在图中的下标 
	system("cls");
	printf("\n以%c为起始顶点的Prim最小生成树的边集为:\n",ch);
	printf("\n  head\t tail\t weight\n");
	printf("-------------------------\n");
	for (j=0; j<G.vexnum; j++)
		if (j!=k)  //无向图的邻接矩阵对角线为0 
		{
			closedge[j].adjvex = ch; //初始化adjvex 
			closedge[j].lowcost = G.arc[k][j]; //ch的所有边上的权值依次赋值给lowcost, 
		}
		closedge[k].adjvex = ch;
		closedge[k].lowcost = 0; //表示这个顶点已经放入生成树中(这里为ch,因为以它为起始点),将其在lowcost上相应位置为0, 
		for (i=1; i<G.vexnum; i++)
		{
			j = 0;
			int min = MAX;
			while (j < G.vexnum)
			{
				if (closedge[j].lowcost !=0 && min > closedge[j].lowcost)
				{
					min = closedge[j].lowcost;
					k=j; //得出下一个加入生成树顶点的下标 
				}
				j++; 
			}
			printf("   %c\t  %c\t  %d\n", closedge[k].adjvex, G.vexs[k], closedge[k].lowcost); 
			printf("-------------------------\n");
			closedge[k].lowcost = 0;
			for (j=0; j<G.vexnum; j++)
				if (closedge[j].lowcost != 0 && closedge[j].lowcost > G.arc[k][j]) //判断lowcost中的权值与新加入生成树的顶点的边的大小,这样得出生成树 
				{                                                                  //中所有顶点的边的权值中的最小值,得出下一个顶点的下标 
					closedge[j].lowcost = G.arc[k][j];
					closedge[j].adjvex = G.vexs[k];  //在Lowcost新加入权值后,在adjlist中加入权值对应位置的顶点
				}
		}
}
void CreateEGraph(EGraph &G)
{
	int i = 0; 
	VertexType v1;
	VertexType v2; 
	printf("\n\n请输入无向网G的顶点数和边数(用逗号隔开) : ");
	scanf("%d,%d",&G.vexnum,&G.arcnum);
	fflush(stdin);
	//建立顶点数组 
	for(i=0;i<G.vexnum;i++)
	{
		printf("请输入第%d个顶点的值(以字符型表示) : ",i+1);
		scanf("%c",&G.vexs[i]);
		fflush(stdin);
	}
	i=0;
	while (i<G.arcnum) //k为顶点数 
	{
		printf("\n请输入第%d条边的信息(head,tail,weight):",i+1);
		fflush(stdin);
		scanf("%c,%c,%d", &G.edgelist[i].head,&G.edgelist[i].tail,&G.edgelist[i].weight);
		i++;	
	}
	system("cls");

}
void PrintEGraph(EGraph G)
{
	int i;
	printf("\n当前图的顶点集G.vexs为:\n");
	printf("\n============================================\n");
	for (i=0; i<G.vexnum; i++)
		printf("  %c\t", G.vexs[i]);
	printf("\n============================================\n");
	printf("\n当前图的边集G.edgelist为:\n");
	printf("\n  i\thead\ttail\tweight\n");
	printf("-------------------------------\n");
	for (i=0; i<G.arcnum; i++)
	{
		printf("  %d\t %c\t %c\t %d \n", i+1,G.edgelist[i].head,G.edgelist[i].tail,G.edgelist[i].weight);
		printf("-------------------------------\n");
	}
}
void sort(EGraph &G)
{
	int i, j,swapflag=1;
	EdgeNode t;
	for(i = 0; i <G.arcnum-1&&swapflag; i++)
	{
		swapflag=0;
		for(j = 0; j<G.arcnum-1-i; j++)
			if(G.edgelist[j ].weight > G.edgelist[j+1].weight)
			{t.head= G.edgelist[j].head;
		t.tail=G.edgelist[j].tail;
		t.weight=G.edgelist[j].weight;
		G.edgelist[j].head=G.edgelist[j+1].head;
		G.edgelist[j].tail=G.edgelist[j+1].tail;
		G.edgelist[j].weight=G.edgelist[j+1].weight;
		G.edgelist[j+1].head=t.head;
		G.edgelist[j+1].tail=t.tail;
		G.edgelist[j+1].weight=t.weight;
		swapflag=1;}
	}

}
void MiniSpanTree_Kruscal(EGraph &G)
{
	EdgeNode *TE ; 
	int i,j,k,v,s1,s2,*Vset ;
	TE=(EdgeNode*)malloc((G.vexnum-1)*sizeof(EdgeNode)) ;
	Vset=(int*)malloc(G.vexnum*sizeof(int)) ;
	for (j=0; j<G.vexnum; j++)
		Vset[j]=j  ;     /*   初始化数组Vset[n]  */ 
	sort(G) ;   /*   对表按权值从小到大排序  */
	printf("将图的边集排序后图G为:\n");
	PrintEGraph(G);
	j=0 ; k=0 ;
	while (k< G.vexnum-1&&j< G.arcnum)
	{  
		s1=Vset[locate(G,G.edgelist[j].head)] ;
		s2=Vset[locate(G,G.edgelist[j].tail)] ;
		/*  若边的两个顶点的连通分量编号不同, 边加入到TE中  */
		if  (s1!=s2)
		{  TE[k].head=G.edgelist[j].head ;
		TE[k].tail=G.edgelist[j].tail ;
		TE[k].weight=G.edgelist[j].weight ;         
		k++ ;
		for (v=0; v<G.vexnum; v++)
			if  (Vset[v]==s2)  Vset[v]=s1 ;
		}
		j++ ;
	}
	free(Vset) ;  
	printf("\nKruscal最小生成树中的边集为:\n");
	printf("  i\thead\ttail\tweight\n");
	printf("-------------------------------\n");
	for(j=0;j<G.vexnum-1;j++)
	{
		printf("  %d\t %c\t %c\t %d\n",j+1,TE[j].head,TE[j].tail,TE[j].weight);
		printf("-------------------------------\n");
	} 
}     /*   求最小生成树的Kruskal算法   */
void menu()
{
	printf("\n|===================================|\n");
	printf("|     ****---- 选择式菜单 ----****  |\n");
	printf("|===================================|\n");
	printf("|                                   |\n");
	printf("|         1:创建图G的MGraph存储     |\n");
	printf("|                                   |\n");
	printf("|         2:输出图G的MGraph存储     |\n");
	printf("|                                   |\n");
	printf("|         3:构造普里姆最小生成树    |\n");
	printf("|                                   |\n");
	printf("|         4:创建图G的EGraph存储     |\n");
	printf("|                                   |\n");
	printf("|         5:输出图G的EGraph存储     |\n");
	printf("|                                   |\n");
	printf("|         6:构造克鲁斯卡尔最小生成树|\n");
	printf("|                                   |\n");
	printf("|         0:退出菜单                |\n");
	printf("|                                   |\n");
	printf("|===================================|\n");
}//menu
int main()
{
	MGraph G1;
	EGraph G2;
	char ch;
	int  k;
	int exitflag=0;
	while(!exitflag)
	{ 
		menu();
		printf("请输入你的菜单选项:");
		scanf("%d",&k);
		switch(k){
		case 0: exitflag=1; 
			break;
		case 1: 
			system("cls");
			CreateMGraph(G1);
			system("cls");
			break;
		case 2:
			system("cls");
			PrintMGraph(G1);
			break;
		case 3:
			system("cls");
			printf("PRIM最小生成树过程如下:\n"); 
			printf("\n请输入构造普里姆生成树的起始顶点:");
			fflush(stdin);
			scanf("%c", &ch);
			MiniSpanTree_Prim(G1, ch);
			break;
		case 4:
			system("cls");
			CreateEGraph(G2);
			system("cls");
			break;
		case 5:
			system("cls");
			PrintEGraph(G2);
			break;
		case 6:
			system("cls");
			printf("Kruscal最小生成树过程如下:\n"); 
			MiniSpanTree_Kruscal(G2);
			break;
		default:
			system("cls");
			printf("警告!你给的选项号非法,请重新输入\n");
			break;	}
	}
	return 0;	
}

你可能感兴趣的:(c运营)