Prim算法C语言实现

Prim算法是加权无向图的最小生成树算法,它要求图是连通的,并且权值必须要为正数。它从图中的任意节点开始,依次更新访问节点的集合S,以及其他节点到S的最短距离,最终,当S中包含所有图中节点时,算法结束。

// Prim_algo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct gra{
	int node;
	int w;
	gra* next;
}graph;
typedef struct mst1 {
	int node;
	int w;
}mst;
graph* initial(int size) {
	graph* g = (graph*)malloc(size*sizeof(graph));
	int i;
	for (i = 0; i < size; i++) {
		(g + i)->node = i+1;//图的节点从1开始
		(g + i)->w = 0;
		(g + i)->next = NULL;
	}
	return g;
}
graph* insert(graph* g, int node1,int node2,int weight) {
	//g是一个图节点的数组
	graph* vertex = (graph*)malloc(sizeof(graph));
	vertex->node = node2;
	vertex->w = weight;
	vertex->next = g[node1-1].next;
	g[node1-1].next = vertex;
	graph* vertex2 = (graph*)malloc(sizeof(graph));
	vertex2->node = node1;
	vertex2->w = weight;
	vertex2->next = g[node2 - 1].next;
	g[node2 - 1].next = vertex2;
	return g;
}
void print(graph* G) {
	int i;
	graph* header;
	for (i = 0; i < 8; i++) {
		header = (G + i)->next;
		while (header != NULL) {
			printf("node %d connected to node %d by weight %d\n", (G + i)->node,(header)->node, (header)->w);
			header = header->next;
		}
	}
}
mst findmin(graph* header) {//这个函数的作用是在一个链表中找到 最小权值以及对应节点。
	int min,res;
	mst rest;

	
	min = header->w;
	res = header->node;
	while (header != NULL) {	
		if (header->w < min) {
			min = header->w;
			res = header->node;
		}
		header = header->next;
	}
	
	rest.node = res;
	rest.w = min;
	return rest;
}
int ismember(int value, int* node) {//判断节点(标号)是否已经被遍历
	int i=0;
	int flag=0;
	while (*(node + i) != 0) {
		if (value == *(node + i)) {
			flag = 1;
			break;
		}
		i++;
	}
	if (flag == 1)
		return 1;
	else
		return 0;
}
mst select(int *node, graph* g) {//选择下一个节点,并没有改变图和遍历记录
	int size,i,j,minw,minn;
	mst temp;//随时记录最小节点以及对应权值
	for (size = 0; size < 8; size++) {
		if (*(node + size) == 0)
			break;
	}
	mst* temp1 = (mst*)malloc(size*sizeof(mst));
	for (j = 0; j < size; j++) {//对于每一个已经选进去的节点,都可以从中选最短的节点,如果路径更短,就可以更新
		for (i = 0; i < 8; i++) {
			if ((g + i)->node == node[j]) {
				if ((g + i)->next != NULL) {
					temp = findmin((g + i)->next);
				}
				else {
					temp.w = 1000;
					temp.node = -1;
				}
			}
		}
		(temp1 + j)->node = temp.node;
		(temp1 + j)->w = temp.w;
	}
	minw = (temp1)->w;
	minn = (temp1)->node;
	for (i = 1; i < size; i++) {
		if ((temp1 + i)->w < minw) {
			minw = (temp1 + i)->w;
			minn = (temp1 + i)->node;
		}
	}
	temp.w = minw;
	temp.node = minn;
	return temp;
}
graph* finetune(int* node, graph* g) {//根据现在已遍历的节点,更新无向图,即去掉图中已遍历节点之间的权值。
	int i;
	graph* temp,*header,*p,*pt;
	for (i = 0; i < 8; i++) {
		temp = g + i;
		if (ismember(temp->node, node) == 1) {
			header = temp;//如果这个节点已经遍历过了,在其链表中去掉那些同样出现的节点信息。
			while (header->next != NULL) {
				if (ismember(header->next->node, node) == 1) {
					p = header->next;
					pt = p->next;
					header->next = p->next;
					free(p);
					continue;
				}
				header = header->next;
			}
		}
	}
	return g;
}
int main()
{
	printf("input a undirected graph in 'node node weight' formation:\n");
	int a[10][3];
	int i, j;
	int nodenum = 8;
	for (j = 0; j < 10; j++) {
		for (i = 0; i < 3; i++) {
			scanf_s("%d", &a[j][i]);
		}
	}
	graph* vertices = initial(nodenum);//vertices是一个数组,元素从1~8
	print(vertices);
	for (j = 0; j < 10; j++) {
		vertices = insert(vertices, a[j][0],a[j][1],a[j][2]);
	}
	print(vertices);//vertices是一个无向图,每个边信息都记录了两份。
	srand(time(0));
	int *nodepointer=(int*)malloc(nodenum*sizeof(int));//nodepointer是一个数组,用来存放已遍历过的节点
	int *weightpointer= (int*)malloc(nodenum*sizeof(int));
	mst temp;
	for (i = 0; i < nodenum; i++) {
		*(nodepointer + i) = 0;
		*(weightpointer + i) = 0;
	}
	i = 0;
	while (*(nodepointer + 7) == 0) {
		if (i == 0) {
			*(nodepointer + i) = rand() % nodenum + 1;//先随机选一个节点放入,第一个位置放节点,其余位置放权值
			*(weightpointer + i) = 0;
		}
		else {
			temp = select(nodepointer, vertices);
			*(weightpointer + i) = temp.w;
			*(nodepointer + i) = temp.node;
			vertices=finetune(nodepointer, vertices);
		}
		i += 1;
		for (j = 0; j < 8; j++)
			printf("%2d", *(nodepointer + j));
	}
	print(vertices);
	printf("\n");
	printf("the node sequence is following:\n");
	for (i = 0; i < 8; i++) {
		printf("%2d", *(nodepointer + i));
	}
	printf("\nthe weight sequence is following:\n");
	for (i = 0; i < 8; i++) {
		printf("%2d", *(weightpointer + i));
	}
	system("pause");
    return 0;
}


prim算法是最小生成树的一种贪心算法,它从有权无向图的任意一节点开始。依次将节点加入到已访问节点的集合S中,并且更新其他节点到S的最短距离,当S包含所有节点时,算法结束。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值