您的位置:首页 > 理论基础 > 数据结构算法

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

2017-12-08 23:49 246 查看
/*
严格参照《数据结构(严蔚敏版)》
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++)
{

4000
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
=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
*/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐