数据结构 邻接矩阵+邻接表+bfs+dfs+prim+Kruskal综合

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37667021/article/details/78674390



/*
严格参照《数据结构(严蔚敏版)》
2017.11.30
by kk
*/

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#define infinity 0x3f3f3f3f
#define maxsize 50
using namespace std;
typedef int VertexType;
typedef int EdgeType;

//下面是图的邻接矩阵的定义
typedef struct
{
    EdgeType data;//弧的信息,比如可以用来标志这条边存不存在,权值多少
    char infomation;//可以用来储存弧其他的信息
} Matrix;
typedef struct GraphM
{
    VertexType ver[maxsize];//顶点信息,如名字
    Matrix arc[maxsize][maxsize];//邻接矩阵
    int numVex,numEdge;//顶点个数,边的个数
    int kind;//图的种类
} GraphM;
/*实际运用时
如果弧上的信息不多(比如只有权值),其实就直接可以用用下面的方式定义
typedef struct Graph
{
    int vertex[100];
    int arc[100][100];
    int num_ver,num_edge;
} Mygraph;
*/

//下面是邻接表的定义
typedef struct ENode
{
    VertexType v;//节点的定义
    int weight;//弧的权值
    struct ENode *next;
} ENode;
typedef struct//顶点的定义
{
    VertexType v;
    ENode *first;
} VerNode;
typedef struct//图的定义
{
    VerNode VerList[maxsize];//顶点表
    int numVer,numEdge;//顶点个数,边的个数
    int kind;//图的种类
} GraphL;

int vis[maxsize];

void createGraphMatrix(GraphM &g)//邻接矩阵建图
{
    int i,j;
    scanf("%d%d",&g.numVex,&g.numEdge);
    for(i=0; i<g.numVex; i++)scanf("%d",&g.ver[i]);
    for(i=0; i<g.numVex; i++)
    {
        for(j=0; j<g.numVex; j++)
            g.arc[i][j].data=infinity;
    }
    int x,y,w;
    for(i=0; i<g.numEdge; i++)
    {
        scanf("%d%d%d",&x,&y,&w);
        g.arc[x][y].data=w;
        g.arc[y][x].data=w;//如果是无向图就把这句加上
    }

    for(i=0; i<g.numVex; i++)
    {
        for(j=0; j<g.numVex; j++)
            printf("%d ",g.arc[i][j].data);
        puts("");
    }
}

void createGraphList(GraphL &g)//邻接表建图
{
    int i,j;
    ENode *e;
    scanf("%d%d",&g.numVer,&g.numEdge);
    for(i=0; i<g.numVer; i++)
    {
        scanf("%d",&g.VerList[i].v);
        g.VerList[i].first=NULL;
    }
    int x,y,w;
    for(i=0; i<g.numEdge; i++)
    {
        scanf("%d%d%d",&x,&y,&w);
        e=(ENode *)malloc(sizeof(ENode));
        e->v=y;
        e->weight=w;
        e->next=g.VerList[x].first;
        g.VerList[x].first=e;

//如果是无向图就把下面这段代码加上
//        e=(ENode *)malloc(sizeof(ENode));
//        e->v=x;
//        e->weight=w;
//        e->next=g.VerList[y].first;
//        g.VerList[y].first=e;
    }
}
void dfs_M(GraphM g,int x)//邻接矩阵dfs某个节点
{
    vis[x]=1;
    printf("%d ",g.ver[x]);
    for(int i=0; i<g.numVex; i++)
        if(vis[i]==0&&g.arc[x][i].data!=infinity)dfs_M(g,i);
}
void dfs_Matrix(GraphM g)//dfs整个表(即使不是连通图也可以)
{
    memset(vis,0,sizeof(vis));
    for(int i=0; i<g.numVex; i++)
        if(vis[i]==0)dfs_M(g,i);

}

void dfs_L(GraphL g,int x)//邻接表dfs某个节点
{
    vis[x]=1;
    printf("%d ",g.VerList[x].v);
    ENode *p;
    p=g.VerList[x].first;
    int tmp;
    while(p)
    {
        tmp=p->v;
        if(vis[tmp]==0)
        {
            dfs_L(g,tmp);
        }
        p=p->next;
    }

}

void dfs_List(GraphL g)//邻接表dfs整个图
{
    memset(vis,0,sizeof(vis));
    ENode *p;
    for(int i=0; i<g.numVer; i++)
    {
        if(vis[i]==0)
        {
            dfs_L(g,i);
        }
    }
}
void bfs_M(GraphM g,int x)//邻接矩阵从x点开始广度优先遍历
{
    queue<int>que;
    que.push(x);//入队
    vis[x]=1;//vis标记入口
    int i,tmp;
    while(!que.empty())
    {
        tmp=que.front();
        printf("%d ",g.ver[tmp]);
        que.pop();
        for(i=0; i<g.numVex; i++)
        {
            if(g.arc[tmp][i].data!=infinity&&vis[i]!=1)
            {
                que.push(i);
                vis[i]=1;
            }
        }
    }
}
void bfs_Matrix(GraphM g)//邻接矩阵bfs遍历整个图
{
    memset(vis,0,sizeof(vis));
    for(int i=0; i<g.numVex; i++)
        if(vis[i]==0)bfs_M(g,i);

}

void bfs_L(GraphL g,int x)//邻接表从x点开始bfs遍历
{
    queue<int>que;
    ENode *p;
    que.push(x);
    vis[x]=1;
    int i,tmp;
    while(!que.empty())
    {
        tmp=que.front();
        printf("%d ",g.VerList[tmp].v);
        p=g.VerList[tmp].first;
        que.pop();
        while(p)
        {
            if(vis[p->v]==0)
            {
                que.push(p->v);
                vis[p->v]=1;
            }
            p=p->next;
        }
    }
}

void bfs_List(GraphL g)//邻接表bfs整个图
{
    memset(vis,0,sizeof(vis));
    for(int i=0; i<g.numVer; i++)
        if(vis[i]==0)bfs_L(g,i);

}

void miniSpanTree_Prim(GraphM g,int x)//prim算法求最小生成树
{
    int lowcost[maxsize];
    //用来储存从现在已有的点出发到达为选择点的最短路径,这个最短不是说从某个点到达另外一个点的最短路径,
    //而是说就单条边的长度来说,也就是说这里面保存的值都是某条边的长度
    int adjvex[maxsize];
    int i,j,k;
    for(i=0; i<g.numVex; i++)
        if(i!=x)lowcost[i]=g.arc[x][i].data;
    lowcost[x]=0;
    //若lowcost[i]=0,说明i点已经被选中
    for(i=0; i<g.numVex; i++)
        adjvex[i]=x;//所有的点最开始都是从i出发的

    for(i=1; i<g.numVex; i++)
    {
        int Min=infinity;
        for(j=0; j<g.numVex; j++)//从lowcost数组中找出最短的边
        {
            if(lowcost[j]!=0&&lowcost[j]<Min)
            {
                Min=lowcost[j];
                k=j;
            }
        }

        printf("%d %d %d\n",adjvex[k],k,lowcost[k]);
        lowcost[k]=0;

        for(j=0; j<g.numVex; j++)
        {
            if(lowcost[j]!=0&&g.arc[k][j].data<lowcost[j])//更新lowcost数组和adjvex数组
            {
                lowcost[j]=g.arc[k][j].data;
                adjvex[j]=k;
            }
        }
        //lowcost数组是用来存边长度和寻找最短边的
        //而adjvex是用来记录路径的(就是这棵树的边是从哪个点到哪个点)
    }

}

int pre[maxsize];//用来记录根节点
typedef struct
{
    int start;
    int last;
    int weight;
} Edge;//相当于创建边集
bool cmp( Edge a, Edge b)
{
    return a.weight<b.weight;
}//边集比较
int Find(int x)
{
    int r=x;
    while(r!=pre[r])
    {
        r=pre[r];
    }
    return r;
}//这里其实用到了并查集的思想,找x的根节点
//下面的函数中也有

void MiniSpanTree_Kruskal(GraphM g)
{

    Edge s[100];
    int cnt=0;
    for(int i=0; i<g.numVex; i++)
    {
        for(int j=i; j<g.numVex; j++)
        {
            if(g.arc[i][j].data!=infinity)
            {
                s[cnt].start=i;
                s[cnt].last=j;
                s[cnt].weight=g.arc[i][j].data;
                ++cnt;
            }
        }

    }
    int i,j;
    sort(s,s+cnt,cmp);
//    for(i=0; i<g.numEdge; i++)
//        printf("%d %d %d\n",s[i].start,s[i].last,s[i].weight);

    //以上是将邻接矩阵转换成边集,并按权值从小到大排序

    //pre[]数组初始化, pre[i]=i的意思是每个节点的跟节点都是自己本身
    for(i=0; i<g.numVex; i++)
        pre[i]=i;

    int n,m;
    for(i=0; i<g.numEdge; i++)
    {
        n=Find(s[i].start);
        m=Find(s[i].last);
        //这里n,m分别是这条边两个节点的各自的根节点,如果m,n不等,那么说明
        //m,n不在一个集合中,也就说明没有构成环
        if(n!=m)
        {
            pre[n]=m;//将m节点及其孩子加入n所在的集合
            printf("%d %d %d\n",s[i].start,s[i].last,s[i].weight);

        }

    }


}

int main()
{
//    GraphL G;
//    createGraphList(G);
    GraphM G;
    memset(vis,0,sizeof(vis));
    createGraphMatrix(G);
//    dfs_Matrix(G1);
//    dfs_Matrix(G);
    miniSpanTree_Prim(G,0);
    printf("\n");
    MiniSpanTree_Kruskal(G);

//    bfs_L(G,2);
//     GraphL G2;  l
//    createGraphList(G2);
//    dfs_List(G2);
    printf("\n");

    return 0;
}

/*
5 5
0 1 2 3 4
0 1 9
0 2 2
1 2 3
2 3 5
3 4 1

5 6
0 1 2 3 4
0 1 9
0 2 2
0 4 6
1 2 3
2 3 5
3 4 1

9 15
0 1 2 3 4 5 6 7 8
0 1 10
0 5 11
1 6 16
5 6 17
1 2 18
1 8 12
2 8 8
2 3 22
8 3 21
6 3 24
6 7 19
3 7 16
7 4 7
3 4 20
5 4 26
*/



猜你喜欢

转载自blog.csdn.net/m0_37667021/article/details/78674390