C语言邻接表——最小生成树——prim+kruskal

1.Prim实现

#include<stdio.h>
#include<stdlib.h>
#define MaxVertices 100
#define INF 65535
int graph[MaxVertices][MaxVertices];
typedef char DataType;
//建立边表
typedef struct node
{
	int adjvex;				//指向边表结点
	struct node *nextarc;	//指向下一条边,没有则为NULL
	int info;				//权值
}ArcNode;
//建立顶点表
typedef struct
{
	DataType data[MaxVertices];			//顶点数据
	ArcNode *firstarc;		//指向该顶点的第一个边表结点
}VerNode;
//建立图
typedef struct
{
	VerNode adjlist[MaxVertices];//顶点数组
	int n;						 //总顶点的个数
	int e;						 //总的边数
}ALGraph;

//建立邻接表
void CrateGraph(ALGraph *G)
{
	int i,j, k;
	int v1, v2;									//输入的两个边
	int weight;											//权值
	printf_s("请输入邻接表的总顶点数和边数:");
	scanf_s("%d %d", &G->n, &G->e);
	for (i = 1; i <= G->n; i++)				//prim最小生成树初始化,不用可省略
	{
		for (j = 1; j <= G->e; j++)
		{
			graph[i][j] = INF;
		}
	}
	fflush(stdin);
	printf_s("请输入顶点(回车结束一个输入)\n");
	for (i = 0; i < G->n; i++)
	{
		gets_s(G->adjlist[i].data, MaxVertices);
		G->adjlist[i].firstarc = NULL;					//初始化边头没有连接的边表
	}
	printf_s("请根据顶点的位置从1开始输入两两相邻的边和权值(中间用空格隔开)\n");
	for (k = 0; k < G->e; k++)
	{
		fflush(stdin);
		printf_s("第%d个连接点:", k + 1);
		scanf_s("%d %d %d", &v1, &v2, &weight);			//输入相邻的边和权值
		graph[v1][v2] = weight;
		graph[v2][v1] = weight;
		v1--; v2--;										//按顶点排序从1开始,减去1方便数组计算
		ArcNode *s = (ArcNode *)malloc(sizeof(ArcNode));
		s->info = weight;
		s->adjvex = v2;
		s->nextarc = G->adjlist[v1].firstarc;
		G->adjlist[v1].firstarc = s;
		/*s->nextarc = NULL;								//尾插法
		ArcNode *p;
		p = G->adjlist[v1].firstarc;
		if (p == NULL)
		{
		G->adjlist[v1].firstarc = s;
		}
		else
		{
		while (p->nextarc)
		{
		p = p->nextarc;
		}
		p->nextarc = s;
		}*/

	}
}
//打印邻接表
void DisGraph(ALGraph *G)
{
	int i;
	printf_s("序号\t顶点名称\t\t边表\n");
	for (i = 0; i < G->n; i++)
	{
		printf_s("%d\t", i+1);						//打印序号
		printf_s("%s\t\t->", G->adjlist[i].data);		//打印顶点
		while (G->adjlist[i].firstarc)
		{
			printf_s("%d(%d)->", G->adjlist[i].firstarc->adjvex+1, G->adjlist[i].firstarc->info);
			G->adjlist[i].firstarc = G->adjlist[i].firstarc->nextarc;
		}
		printf_s("NULL\n");
	}
}

//广度优先遍历
int visited[MaxVertices];
typedef struct LoopQueue
{
	int data[MaxVertices];
	int front;
	int rear;
}Queue, *LQueue;
void InitQueue(LQueue Q){  //初始化队列 
	Q->front = Q->rear = 0;
}
int QueueisFull(LQueue Q){ //判断队列是否满了 
	if ((Q->rear + 1) % MaxVertices == Q->front){
		return -1;  //已满 
	}
	else{
		return 1;
	}
}
int QueueisEmpty(LQueue Q){//判断队列是否为空 
	if (Q->front == Q->rear){
		return -1;
	}
	return 1;
}
void EnQueue(LQueue Q, int i){ //入队列 
	if (!QueueisFull(Q)){
		Q->data[Q->rear] = i;
		Q->rear = (Q->rear + 1) % MaxVertices;  //队尾指针后移 
	}
}
void DeQueue(LQueue Q, int *k){ //出队列 
	if (!QueueisEmpty(Q)){
		*k = Q->data[Q->front];
		Q->front = (Q->front + 1) % MaxVertices;
	}
}
void BFS(ALGraph *G)
{

	Queue Q;
	for (int i = 0; i < G->n; i++)
	{
		visited[i] = 0;
	}
	InitQueue(&Q);														 //初始化队列 
	for (int i = 0; i < G->n; i++)
	{
		visited[i] = 1;
		printf("%s ", G->adjlist[i].data);
		EnQueue(&Q, i);
		while (!QueueisEmpty(&Q))
		{
			DeQueue(&Q, &i);												 //这里不断的修改i的值!! 
			ArcNode *e = G->adjlist[i].firstarc;						 //i顶点的邻接链表的第一个结点
			while (e)
			{															//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点 
				if (!visited[e->adjvex])
				{													    // adjvex是e所表示的结点下标 
					visited[e->adjvex] = 1;
					printf("\t%s", G->adjlist[e->adjvex].data);
					EnQueue(&Q, e->adjvex);							    //将该结点入队 
				}
				e = e->nextarc;											//遍历i的下一个邻接点 
			}
			printf_s("\n");
		}
	}
}
//深度优先遍历
int visited1[MaxVertices];
void DFS(ALGraph *G, int i)
{
	ArcNode *p;
	visited1[i] = 1;
	printf_s("%s ", G->adjlist[i].data);
	p = G->adjlist[i].firstarc;
	while (p)
	{
		if (!visited1[p->adjvex])
		{
			DFS(G, p->adjvex);
		}
		p = p->nextarc;
	}
}
//广度优先遍历
void BFSTravel(ALGraph *G)
{
	int v, front, rear;
	ArcNode *p;
	int queue[MaxVertices];
	front = rear = -1;
	for (v = 0; v < G->n; v++)
	{
		visited[v] = 0;
	}
	v = 0;
	visited[v] = 1;
	printf_s("%c ", G->adjlist[v].data);
	rear = (rear + 1) % MaxVertices;
	queue[rear] = v;
	while (front < rear)
	{
		front = (front + 1) % MaxVertices;
		v = queue[front];
		p = G->adjlist[v].firstarc;
		while (p != NULL)
		{
			if (visited[p->adjvex] == 0)
			{
				visited[p->adjvex] = 1;
				printf_s("%c ", G->adjlist[p->adjvex].data);
				rear = (rear + 1) % MaxVertices;
				queue[rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
}
void DFSTravel(ALGraph *G)
{
	int i;
	for (i = 0; i < G->n; i++)
	{
		visited1[i] = 0;
	}
	for (i = 0; i < G->n; i++)
	{
		if (!visited1[i])
		{
			DFS(G, i);
		}
	}
}

//prim最小生成树

int Prim(int graph[][MaxVertices], int n)
{
	int lowcost[MaxVertices], mst[MaxVertices];
	/*
	lowcost[i]记录以i为终点的边的最小权值,当lowcost[i]=0时表示终点i加入生成树
	mst[i]记录对应lowcost[i]的起点,当mst[i]=0时表示起点i加入生成树
	*/
	int i, j, min, minid, sum = 0;
	for (i = 2; i <= n; i++)				//默认选择1号节点加入生成树,从2号节点开始初始化
	{
		lowcost[i] = graph[1][i];			//最短距离初始化为其他节点到1号节点的距离
		mst[i] = 1;							//标记所有节点的起点皆为默认的1号节点
	}
	mst[1] = 0;								//标记1号节点加入生成树
	for (i = 2; i <= n; i++)				//n个节点至少需要n-1条边构成最小生成树
	{
		min = INF;
		minid = 0;

		for (j = 2; j <= n; j++)			 //找满足条件的最小权值边的节点minid
		{
			if (lowcost[j] < min && lowcost[j] != 0)  //边权值较小且不在生成树中
			{
				min = lowcost[j];
				minid = j;
			}
		}
		printf("%d - %d : %d\n", mst[minid], minid, min);  //输出生成树边的信息:起点,终点,权值
		sum += min;							//累加权值
		lowcost[minid] = 0;					//标记节点minid加入生成树

		for (j = 2; j <= n; j++)			//更新当前节点minid到其他节点的权值
		{
			if (graph[minid][j] < lowcost[j])  ///发现更小的权值
			{
				lowcost[j] = graph[minid][j];  //更新权值信息
				mst[j] = minid;				//更新最小权值边的起点
			}
		}
	}
	return sum;								//返回最小权值和
}

void main()
{
	ALGraph G;
	CrateGraph(&G);
	printf_s("\n");
	DisGraph(&G);
	printf_s("\n最小生成树的权值之和:%d\n", Prim(graph, G.n));
}

在这里插入图片描述
2.kruskal实现

#include<stdio.h>
#include<stdlib.h>
#define MaxVertices 100
#define INF 65535
int sum = 0;
//建立边表
typedef struct node
{
	int adjvex;			//该边指向的结点位置
	struct node* next;	//指向下一条边
	int info;			//权重
}ArcNode;
//建立顶点表
typedef struct
{
	char data;
	ArcNode *first;
}VerNode;
//定义边集数组
typedef struct Edge
{
	int v1;
	int v2;
	int weight;
}Edge;
//建立连接表
typedef struct
{
	VerNode adjList[MaxVertices];//邻接表的顶点存放数组
	int n, e;					 //顶点数,边数
	Edge *p;					//存放边集的数组
	int *m;						//存放
}AdjList;

//生成无向邻接表
void CreateGraph1(AdjList *L)
{
	int i, j, a, b, c;
	ArcNode *s;										//边表
	printf_s("请输入总顶点数和总边数:\n");
	scanf_s("%d%d", &L->n, &L->e);
	L->p = (Edge*)malloc(sizeof(Edge)*(L->e + 1));
	L->m = (int *)malloc(sizeof(int)*L->n);
	printf_s("建立顶点表:\n");
	for (i = 0; i < L->n; i++)
	{
		scanf_s("%d", &L->adjList[i].data);
		L->m[i] = L->adjList[i].data;				//最小生成树算法顶点数组
		L->adjList[i].first = NULL;					//初始化当前顶点指向的边表全部为空
	}
	//头插法创建边表
	printf_s("建立边表:\n");
	for (i = 0; i < L->e; i++)
	{
		printf_s("请输入有连接的顶点:");
		scanf_s("%d%d%d", &a, &b, &c);
		L->p[i].v1 = a;
		L->p[i].v2 = b;
		L->p[i].weight = c;
		a -= 1; b -= 1;								//输入顶点从一开始,减去1后方便数组存储
		s = (ArcNode*)malloc(sizeof(ArcNode));	    //边表申请存储空间
		s->adjvex = b;								//边表的数据域赋值,指向边表的结点位置
		s->info = c;								//两个连接的权重

		s->next = NULL;								//尾插法
		ArcNode *p;
		p = L->adjList[a].first;
		if (p == NULL)
		{
			L->adjList[a].first = s;
		}
		else
		{
			while (p->next)
			{
				p = p->next;
			}
			p->next = s;
		}

		/*
		s->next = L->adjList[a].first;				//头插法
		L->adjList[a].first = s;
		*/

		/*加入这部分就是无向邻接表
		s = (ArcNode*)malloc(sizeof(ArcNode));
		s->adjvex = a;
		s->next = L->adjList[b].first;
		L->adjList[b].first = s;
		*/
	}
	for (i = 0; i < L->e; i++)						//根据权值冒泡排序
	{
		for (j = L->e - 1; j > i; j--)
		{
			if (L->p[i].weight > L->p[j].weight)
			{
				L->p[L->e] = L->p[i];
				L->p[i] = L->p[j];
				L->p[j] = L->p[L->e];
			}
		}
	}
}

int Find(int *parent, int g)				//通过parent[]找到可连接的边
{
	while (parent[g] != 0)
	{
		g = parent[g];
	}
	return g;
}
int Finish(AdjList *G, int *parent)		//判断生成树是否完成,完成的标志是生成树的边等于顶点的数量减1
{
	int i, n = 0;

	for (i = 0; i<G->n; i++)
	{
		if (parent[i])
		{
			n++;
		}
	}
	if (n == G->n - 1)
	{
		return 1;
	}
	return 0;
}
int FindPeak(AdjList *G, int g)		//找到顶点的下标
{
	int i;
	for (i = 0; i<G->n; i++)
	{
		if (G->m[i] == g)
			return i;
	}
	return -1;
}
int MinTree_Kruskal(AdjList *G)
{
	int i, a, b;

	int parent[MaxVertices];

	for (i = 0; i<G->n; i++)		//初始化parent[]
	{
		parent[i] = 0;
	}
	printf_s("编号\t顶点\t生成树\n");
	for (i = 0; i<G->e; i++)
	{
		a = Find(parent, FindPeak(G, G->p[i].v1));
		b = Find(parent, FindPeak(G, G->p[i].v2));

		if (a != b)				//如果a==b则表是a和b在同一颗生成树上,如果a和b连接则为生成环,不符合生成树
		{
			parent[a] = b;
			printf_s("%d\t%c\t",i+1,i+'a');
			printf("%d->%d = %d\n", G->p[i].v1, G->p[i].v2, G->p[i].weight);
			sum += G->p[i].weight;
		}
		if (Finish(G, parent))		//完成后返回
		{
			return sum;
		}
	}
	return -1;
}

void DisGraph1(AdjList *L)
{
	int i;
	for (i = 0; i < L->n; i++)
	{
		printf_s("%d->", i + 1);
		while (1)
		{
			if (L->adjList[i].first == NULL)
			{
				break;
			}
			printf_s("%d(%d)->", L->adjList[i].first->adjvex + 1, L->adjList[i].first->info);
			L->adjList[i].first = L->adjList[i].first->next;
		}
		printf_s("NULL\n");
	}
}
void main()
{
	AdjList *L = (AdjList*)malloc(sizeof(AdjList));
	CreateGraph1(L);
	printf_s("\n");
	printf_s("权值和:%d\n", MinTree_Kruskal(L));
}

在这里插入图片描述

  • 16
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

madkeyboard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值