Prim算法(最小生成树)

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值