邻接矩阵DFS/BFS/Djistra/Prim

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MVNum 100        // 顶点数组的长度
#define MaxInt 32767      // 边的权值置为最大值
#define OK 1

typedef char VerTexType;  // 假设顶点的数据类型为字符型
typedef int ArcType;      // 表示边的权值,类型为整形
typedef int Status;

typedef struct
{
    VerTexType vexs[MVNum];   // 顶点表
    ArcType arcs[MVNum][MVNum];  // 邻接矩阵
    int vexnum, arcnum;       // 图的当前点数和边数
} AMGraph;
typedef struct
{
    VerTexType adjvex; // 记录权值最小的边的起始点
    ArcType lowcost; // 记录该边的权值
} closeEdge;
closeEdge closedge[MVNum]; // 辅助数组,用于每次筛选出权值最小的边的邻接点
Status LocateVex(AMGraph G, VerTexType v)
{
    for (int i = 0; i < G.vexnum; ++i)
        if (G.vexs[i] == v)
            return i;
    return -1;
}

Status CreateUDN(AMGraph* G)
{
    VerTexType v1, v2;
    int w, i, j;
    printf("请输入总顶点数,总边数,以空格隔开:");
    scanf("%d %d", &G->vexnum, &G->arcnum);
    printf("\n请输入点的名称,如a\n");
    for (i = 0; i < G->vexnum; ++i)
    {
        printf("请输入第%d个点的名称:", i + 1);
        scanf(" %c", &G->vexs[i]);
    }
    for (i = 0; i < G->vexnum; ++i)
    {
        for (j = 0; j < G->vexnum; ++j)
        {
            G->arcs[i][j] = MaxInt;
        }
    }
    printf("\n输入边依附的顶点及权值,如AB 5\n");
    for (int k = 0; k < G->arcnum; ++k)
    {
        printf("请输入第%d条边依附的顶点及权值:", k + 1);
        scanf(" %c %c %d", &v1, &v2, &w);
        i = LocateVex(*G, v1);
        j = LocateVex(*G, v2);
        G->arcs[i][j] = w;
        G->arcs[j][i] = G->arcs[i][j];
    }
    return OK;
}

void DispAMGraph(AMGraph G)
{
    printf("\n无向网G的邻接矩阵如下:\n");
    printf("输出无向网的邻接矩阵\n");
    for (int i = 0; i < G.vexnum; ++i)
    {
        for (int j = 0; j < G.vexnum; ++j)
        {
            printf("%7d", G.arcs[i][j]);
        }
        printf("\n");
    }
}
int Min(AMGraph G)
{
    int minNum = MaxInt;
    int k = -1;
    for (int i = 0; i < G.vexnum; ++i)
    {
        if (closedge[i].lowcost != 0 && closedge[i].lowcost < minNum)
        {
            minNum = closedge[i].lowcost;
            k = i;
        }
    }
    return k;
}

// Prim算法构造最小生成树
void MiniSpanTree_Prim(AMGraph G, VerTexType u)
{
    int sum = 0; // 记录最小生成树最小权值之和
    printf("******利用普里姆算法构造最小生成树结果:******\n");
    VerTexType u0, v0; // 声明两个临时顶点变量
    int k;
    k = LocateVex(G, u); // 起点位置,k为顶点u的下标
    for (int j = 0; j < G.vexnum; ++j) // 对V-U的每个顶点vi,初始化closedge[i]
    {
        if (j != k)
        {
            closedge[j].adjvex = u; // 最小边在U中的顶点为u
            closedge[j].lowcost = G.arcs[k][j]; // 初始化权值
        }
    }
    closedge[k].lowcost = 0; // 初始,U = { u }

    for (int i = 1; i < G.vexnum; ++i)
    { // 选择其余n-1个顶点,生成n-1条边(n = G.vexnum )
        k = Min(G); // 求出T的下一个结点:closedge[k]存有当前最小边

        u0 = closedge[k].adjvex; // u0为最小边的一个顶点,u0 属于 U
        v0 = G.vexs[k]; // v0为最小边的另一个顶点,v0 属于 V-U
        printf("边  %c--->%c%7d\n", u0, v0, closedge[k].lowcost); // 输出当前的最小边(u0,v0)
        sum += closedge[k].lowcost;
        closedge[k].lowcost = 0; // 第k个顶点并入U集
        for (int j = 0; j < G.vexnum; ++j)
            if (G.arcs[k][j] < closedge[j].lowcost)
            { // 新顶点并入U后重新选择最小边
                closedge[j].adjvex = G.vexs[k];
                closedge[j].lowcost = G.arcs[k][j];
            }
    }
    printf("最小生成树的代价之和 = %d\n", sum);
}
// BFS
void BFS(AMGraph G, int v)
{
    int visited[MVNum] = { 0 }; // 0表示未访问,1表示已访问
    int queue[MVNum];
    int front = 0, rear = 0;

    printf("\nBFS遍历结果:\n");

    printf("%c ", G.vexs[v]);
    visited[v] = 1;
    queue[rear++] = v;

    while (front < rear)
    {
        int current = queue[front++];
        for (int i = 0; i < G.vexnum; ++i)
        {
            if (G.arcs[current][i] != MaxInt && !visited[i])
            {
                printf("%c ", G.vexs[i]);
                visited[i] = 1;
                queue[rear++] = i;
            }
        }
    }
    printf("\n");
}

// DFS
void DFS(AMGraph G, int v, int visited[MVNum])
{
    printf("%c ", G.vexs[v]);
    visited[v] = 1;

    for (int i = 0; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] != MaxInt && !visited[i])
        {
            DFS(G, i, visited);
        }
    }
}

void DFSTraverse(AMGraph G)
{
    int visited[MVNum] = { 0 };

    printf("\nDFS遍历结果:\n");

    for (int i = 0; i < G.vexnum; ++i)
    {
        if (!visited[i])
        {
            DFS(G, i, visited);
        }
    }
    printf("\n");
}
void ShortestPath_Dijkstra(AMGraph G, VerTexType v)
{
    int dist[MVNum]; // 存储源顶点到各顶点的最短距离
    int visited[MVNum] = { 0 }; // 标记顶点是否已访问
    int parent[MVNum]; // 存储最短路径中每个顶点的父节点

    printf("\n******Dijkstra算法寻找最短路径******\n");

    // 初始化
    for (int i = 0; i < G.vexnum; ++i)
    {
        dist[i] = MaxInt;
        visited[i] = 0;
        parent[i] = -1;
    }

    int sourceIndex = LocateVex(G, v);
    dist[sourceIndex] = 0;

    for (int i = 0; i < G.vexnum - 1; ++i)
    {
        // 找到未访问的顶点中距离最小的顶点
        int u = -1;
        int minDist = MaxInt;
        for (int j = 0; j < G.vexnum; ++j)
        {
            if (!visited[j] && dist[j] < minDist)
            {
                u = j;
                minDist = dist[j];
            }
        }

        if (u == -1)
            break;

        visited[u] = 1;

        // 更新与选定顶点相邻顶点的距离值
        for (int k = 0; k < G.vexnum; ++k)
        {
            if (!visited[k] && G.arcs[u][k] != MaxInt && dist[u] + G.arcs[u][k] < dist[k])
            {
                dist[k] = dist[u] + G.arcs[u][k];
                parent[k] = u;
            }
        }
    }

    // 打印最短路径
    for (int i = 0; i < G.vexnum; ++i)
    {
        if (i != sourceIndex)
        {
            printf("从%c到%c的最短路径:", G.vexs[sourceIndex], G.vexs[i]);
            int j = i;
            while (j != sourceIndex)
            {
                printf("%c <- ", G.vexs[j]);
                j = parent[j];
            }
            printf("%c ", G.vexs[sourceIndex]);
            printf("  距离:%d\n", dist[i]);
        }
    }
}

int main(void)
{
    VerTexType v;
    AMGraph G;
    CreateUDN(&G);
    DispAMGraph(G);
    printf("请输入起点:");
    scanf(" %c", &v);
    BFS(G, LocateVex(G, v));
    DFSTraverse(G);
    MiniSpanTree_Prim(G, v);
    ShortestPath_Dijkstra(G, v);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weixin_45230280

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

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

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

打赏作者

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

抵扣说明:

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

余额充值