C语言数据结构学习笔记(18)-无向网图的DFS和BFS遍历及最小生成树Prim、Kruskal算法

/*
无向网图的DFS和BFS遍历及最小生成树Prim、Kruskal算法
输出结果:
请输入顶点和边的个数:6 9
请输入第1个顶点的信息:v0
请输入第2个顶点的信息:v1
请输入第3个顶点的信息:v2
请输入第4个顶点的信息:v3
请输入第5个顶点的信息:v4
请输入第6个顶点的信息:v5
请输入第1条边(Vi, Vj)两个顶点的下标及权值:0 1 10
请输入第2条边(Vi, Vj)两个顶点的下标及权值:0 2 50
请输入第3条边(Vi, Vj)两个顶点的下标及权值:0 5 30
请输入第4条边(Vi, Vj)两个顶点的下标及权值:1 4 60
请输入第5条边(Vi, Vj)两个顶点的下标及权值:2 3 40
请输入第6条边(Vi, Vj)两个顶点的下标及权值:2 5 20
请输入第7条边(Vi, Vj)两个顶点的下标及权值:3 5 70
请输入第8条边(Vi, Vj)两个顶点的下标及权值:3 4 90
请输入第9条边(Vi, Vj)两个顶点的下标及权值:4 5 80
        v0      v1      v2      v3      v4      v5
v0      ∞       10      50      ∞       ∞       30
v1      10      ∞       ∞       ∞       60      ∞
v2      50      ∞       ∞       40      ∞       20
v3      ∞       ∞       40      ∞       90      70
v4      ∞       60      ∞       90      ∞       80
v5      30      ∞       20      70      80      ∞

DFS:    v0      v1      v4      v3      v2      v5
BFS:    v0      v1      v2      v5      v4      v3

请输入最小生成树的起始顶点:2
Prim:   (2, 5)20-->(5, 0)30-->(0, 1)10-->(2, 3)40-->(1, 4)60-->end

Kruskal:(0, 1)10-->(2, 5)20-->(0, 5)30-->(2, 3)40-->(1, 4)60-->end
请按任意键继续. . .
*/
# include <stdio.h>
# include <stdlib.h>
# define MAX_VEX 10//最大顶点个数
# define INF 0x3f3f3f3f//无穷大
# define SIZE 5//顶点信息最大字符串个数+1
typedef char VertexType[SIZE];
typedef int EdgeType;
typedef struct{
    VertexType vexs[MAX_VEX];//顶点数组
    EdgeType arc[MAX_VEX][MAX_VEX];//边表
    int vexNum, edgeNum;//图中顶点和边的个数
}MGraph;//无向网图邻接矩阵
struct minEdge{
    int adjvex;//顶点下标
    int lowcost;//最小权值
}minEdge[MAX_VEX];//创建最小权值边数组
typedef struct{
    int begin;//边起始顶点
    int end;//边尾部顶点
    int weight;//权值
}EdgeNode;
bool visited[MAX_VEX];//访问标志数组
void CrateMGraph(MGraph * G);//创建无向网图
void PrintMGraph(MGraph G);//打印邻接矩阵
void DFSTraverse(MGraph G);//深度优先遍历
void DFS(MGraph G, int i);//深度优先递归
void BFSTraverse(MGraph G);//广度优先遍历
void Prim(MGraph G, int start);//最小生成树-Prim算法
void Kruskal(MGraph G);//最小生成树-Kruskal算法
void InitEdge(MGraph G, EdgeNode * Edge);//初始化Edge边数组
void sort(EdgeNode * Edge, int n);//排序
int Find(int * parent, int m);//找根节点

int main(void)
{    
    int start;
    MGraph G;
    CrateMGraph(&G);
    PrintMGraph(G);
    DFSTraverse(G);
    BFSTraverse(G);
    printf("请输入最小生成树的起始顶点:");
    scanf("%d", &start);
    printf("Prim:\t");
    Prim(G, start);
    printf("end\n");
    printf("\nKruskal:");
    Kruskal(G);
    printf("end\n");
    system("pause");
    return 0;
}
//创建无向网图
void CrateMGraph(MGraph * G)
{
    int i, j, k, w;
    printf("请输入顶点和边的个数:");
    scanf("%d %d", &G->vexNum, &G->edgeNum);
    for(i = 0; i < G->vexNum; i++)
    {
        printf("请输入第%d个顶点的信息:", i+1);
        scanf("%s", &G->vexs[i]);
    }
    for(i = 0; i < G->vexNum; i++)
        for(j = 0; j < G->vexNum; j++)
            G->arc[i][j] = INF;
    for(k = 0; k < G->edgeNum; k++)
    {
        printf("请输入第%d条边(Vi, Vj)两个顶点的下标及权值:", k+1);
        scanf("%d %d %d", &i, &j, &w);
        G->arc[i][j] = w;
        G->arc[j][i] = G->arc[i][j];
    }
}
//打印邻接矩阵
void PrintMGraph(MGraph G)
{    
    int i, j;
    for(i = 0; i < G.vexNum; i++)
        printf("\t%s", G.vexs[i]);
    printf("\n");
    for(i = 0; i < G.vexNum; i++)
    {
        printf("%s\t", G.vexs[i]);
        for(j = 0; j < G.vexNum; j++)
        {    
            if(G.arc[i][j] == INF)
                printf("∞\t");
            else
                printf("%d\t", G.arc[i][j]);
        }
        printf("\n");
    }
}
//深度优先遍历
void DFSTraverse(MGraph G)
{    
    int i;
    for(i = 0; i < G.vexNum; i++)
        visited[i] = false;
    printf("\nDFS:\t");
    for(i = 0; i < G.vexNum; i++)
    {
        if(!visited[i])
            DFS(G, i);
    }
    printf("\n");
}
//深度优先递归
void DFS(MGraph G, int i)
{    
    int j;
    visited[i] = true;
    printf("%s\t", G.vexs[i]);
    for(j = 0; j < G.vexNum; j++)
    {
        if(!visited[j] && G.arc[i][j] != INF)
            DFS(G, j);
    }
}
//广度优先遍历
void BFSTraverse(MGraph G)
{    
    int i , j;
    for(i = 0; i < G.vexNum; i++)
        visited[i] = false;
    int Queue[MAX_VEX];//队列存放顶点对应下标
    int front = 0, rear = 0;//队首队尾下标
    printf("BFS:\t");
    for(i = 0; i < G.vexNum; i++)
    {
        if(!visited[i])
        {    
            visited[i] = true;
            printf("%s\t", G.vexs[i]);
            rear = (rear + 1) % MAX_VEX;
            Queue[rear] = i; //将此顶点下标入队
            while(rear != front)//当队列不为空
            {    
                front = (front + 1) % MAX_VEX;
                i = Queue[front];//队首元素出队赋值给i,便于寻找一下个邻接点
                for(j = 0; j < G.vexNum; j++)
                {
                    if(!visited[j] && G.arc[i][j] != INF)//找到未被访问的顶点并且属于当前顶点i的邻接点
                    {
                        visited[j] = true;
                        printf("%s\t", G.vexs[j]);
                        rear = (rear + 1) % MAX_VEX;
                        Queue[rear] = j;//将找到顶点循环依次序入队
                    }
                }
            }
        }
    }
    printf("\n\n");
}
//最小生成树-Prim算法
void Prim(MGraph G, int start)
{    
    int i;
    for(i = 0; i < G.vexNum; i++)
    {    
        minEdge[i].adjvex = start;
        minEdge[i].lowcost = G.arc[start][i];
    }
    minEdge[start].lowcost = 0;//lowcost数组值为0表示该下标对应顶点已经并入集合
    for(i = 0; i < G.vexNum - 1; i++)//n个顶点最小生成树共n-1条边
    {    
        int j = 0;
        int k = 0;
        int min = INF;
        //循环找寻最小权值
        while(j < G.vexNum)
        {
            if(minEdge[j].lowcost != 0 && minEdge[j].lowcost < min)
            {
                min = minEdge[j].lowcost;
                k = j;
            }
            j++;
        }
        printf("(%d, %d)%d-->", minEdge[k].adjvex, k, minEdge[k].lowcost);
        minEdge[k].lowcost  = 0;//将lowcost数组值置0表示该下标对应顶点已经并入集合
        //更新lowcost数组值,若新点位k的邻接点有最小权值边则替换
        for(j = 0; j < G.vexNum; j++)
        {
            if(minEdge[j].lowcost != 0 && G.arc[k][j] < minEdge[j].lowcost)
            {
                minEdge[j].lowcost = G.arc[k][j];
                minEdge[j].adjvex = k;
            }
        }
    }
}
//最小生成树-Kruskal算法
void Kruskal(MGraph G)
{    
    int i, j;
    EdgeNode * Edge = (EdgeNode*)malloc(G.edgeNum * sizeof(EdgeNode));
    if(!Edge)
        exit(-1);
    int * parent = (int*)malloc(G.vexNum * sizeof(int));
    if(!parent)
        exit(-1);
    //初始化parent数组判断是否构成回路
    for(i = 0; i < G.vexNum; i++)
        parent[i] = -1;
    InitEdge(G, Edge);
    sort(Edge, G.edgeNum);//对边数组按权值升序排序
    int vex1, vex2, cnt;
    for(cnt = 0, i = 0; i < G.edgeNum; i++)
    {    
        vex1 = Find(parent, Edge[i].begin);
        vex2 = Find(parent, Edge[i].end);
        //判断是否构成环路,若两个顶点不具有相同根则不构成回路
        if(vex1 != vex2)
        {    
            printf("(%d, %d)%d-->", Edge[i]);
            parent[vex2] = vex1;//表示此顶点在生成树集合中
            cnt++;
            if(cnt == G.vexNum - 1)
                break;
        }
    }
    free(Edge);
    Edge = NULL;
    free(parent);
    parent = NULL;
}
//初始化Edge边数组
void InitEdge(MGraph G, EdgeNode * Edge)
{
    int k = 0;
    for(int i = 0; i < G.vexNum; i++)
    {
        for(int j = 0; j < G.vexNum; j++)
        {
            if(i < j && G.arc[i][j] != INF)
            {
                Edge[k].begin = i;
                Edge[k].end = j;
                Edge[k].weight = G.arc[i][j];
                k++;
            }
        }
    }
}
//查找根结点
int Find(int * parent, int m)
{    
    while(parent[m] > -1)
        m = parent[m];
    return m;
}
//排序
void sort(EdgeNode * Edge, int n)
{    
    EdgeNode Temp;
    for(int i = 0; i < n - 1; i++)
    {
        for(int j = 0; j < n - 1 - i; j++)
        {    
            if(Edge[j].weight > Edge[j+1].weight)
            {
                Temp = Edge[j];
                Edge[j] = Edge[j+1];
                Edge[j+1] = Temp;
            }
        }
    }
}
 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值