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包含所有节点时,算法结束。