Prim算法简介:
图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
图:
代码实现:
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 9999 // 意为没有路
/*
循环矩阵, 最小权值的x, y记录到链表内
按权值从小到大插入。
*/
typedef struct Node
{
int x, y; // x: 行 y: 列
struct Node *next;
} Node, *NodePtr;
int graph[9][9] = {
{0, 10, INFINITY, INFINITY, INFINITY, 11, INFINITY, INFINITY, INFINITY},
{10, 0, 18, INFINITY, INFINITY, INFINITY, 16, INFINITY, 12},
{INFINITY, 18, 0, 22, INFINITY, INFINITY, INFINITY, INFINITY, 8},
{INFINITY, INFINITY, 22, 0, 20, INFINITY, 24, 16, 21},
{INFINITY, INFINITY, INFINITY, 20, 0, 26, INFINITY, 7, INFINITY},
{11, INFINITY, INFINITY, INFINITY, 26, 0, 17, INFINITY, INFINITY},
{INFINITY, 16, INFINITY, 24, INFINITY, 17, 0, 19, INFINITY},
{INFINITY, INFINITY, INFINITY, 16, 7, INFINITY, 19, 0, INFINITY},
{INFINITY, 12, 8, 21, INFINITY, INFINITY, INFINITY, INFINITY, 0}
};
// 记录最小生成树
int smallTree[9][9] = {0};
NodePtr Init_headNode();
void InsertLinkList(NodePtr *headNode, int x, int y);
NodePtr getNode(NodePtr *headnode);
void destoryNode(NodePtr *headNode);
void prim(NodePtr headNode, int start);
// 初始化链表
NodePtr Init_headNode()
{
NodePtr headNode = (NodePtr)malloc(sizeof(Node));
if ( !headNode )
{
printf("Failure!\n");
exit(1);
}
headNode->next = NULL;
return headNode;
}
// 插入链表, 从小到大
void InsertLinkList(NodePtr *headNode, int x, int y)
{
NodePtr newNode = (NodePtr)malloc(sizeof(Node));
if ( !newNode )
{
printf("Failure!\n");
exit(1);
}
newNode->x = x;
newNode->y = y;
newNode->next = NULL;
if ( !(*headNode)->next )
{
(*headNode)->next = newNode;
}
else
{
NodePtr temp = (*headNode);
while ( temp->next )
{
if ( graph[x][y] <= graph[temp->next->x][temp->next->y] )
{
newNode->next = temp->next;
temp->next = newNode;
return;
}
temp = temp->next;
}
temp->next = newNode;
}
}
// 取出最小权值的位置
NodePtr getNode(NodePtr *headnode)
{
NodePtr minNode = (*headnode)->next;
(*headnode)->next = minNode->next;
return minNode;
}
void destoryNode(NodePtr *headNode)
{
NodePtr temp;
while ( (*headNode) )
{
temp = (*headNode);
(*headNode) = (*headNode)->next;
free(temp);
}
}
// 生成最小树
void prim(NodePtr headNode, int start)
{
NodePtr minIndex;
int i = start;
int cnt = 1; // 记录走过结点的个数
while ( cnt < 9 )
{
// 遍历矩阵, 将带权的路径加入链表
for (int j = 0; j < 9; j++)
{
if ( graph[i][j] != 0 && graph[i][j] < INFINITY )
{
InsertLinkList(&headNode, i, j);
}
}
while ( 1 )
{
minIndex = getNode(&headNode);
if ( graph[minIndex->x][minIndex->y] != 0 )
{
printf("%c ", minIndex->y + 65);
cnt ++;
break;
}
else
{
free(minIndex);
}
}
// 记录最小生成树路径
smallTree[minIndex->x][minIndex->y] = graph[minIndex->x][minIndex->y];
// 标记走过的路
for (int j = 0; j < 9; j++)
{
graph[j][minIndex->y] = 0;
}
i = minIndex->y;
// 用完直接free掉
free(minIndex);
}
}
int main(void)
{
char start;
int y;
NodePtr headNode = Init_headNode();
printf("Input start point: ");
scanf("%c", &start);
y = start - 65;
printf("%c ", start);
// 标记起始点
for (int i = 0; i < 9; i++)
{
graph[i][y] = 0;
}
prim(headNode, y);
// 最小生成树邻接矩阵
printf("\n最小生成树的邻接矩阵:\n");
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
printf("%3d ", smallTree[i][j]);
}
printf("\n");
}
return 0;
}
注: 输入的时候需要输入大写的字母,代码测试次数不多,如遇BUG望告知!
运行结果:
>>Input start point: A
A B F I C G H E D
最小生成树的邻接矩阵:
0 10 0 0 0 11 0 0 0
0 0 0 0 0 0 16 0 12
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 19 0
0 0 0 16 7 0 0 0 0
0 0 8 0 0 0 0 0 0