图的存储结构
1.二维数组邻接矩阵存储
定义int G[101][101]; G[i][j]的值,表示从点i到点j的边的权值,定义如下:
2.二维数组邻接矩阵存储的优化 (多用于稠密图)
int g[101][101],num[101]; //num[i]记录与顶点i相连的边数,增强顶点的联系 double w[101][101]; cin >> e; for (k = 1; k <= e; k++) { cin >> i >> j >> v; //读入两个顶点序号及权值 w[i][j]=w[j][i]=v; g[i][++num[i]] = j; //对于不带权的图g[i][j]=1 g[j][++num[j]] = i; //无向图的对称性, 有向图则不要! } 查询:O(e)//边数 for(int i=1;i<=n;i++) for(int j=1;j<=num[i];j++) { 直接调用w[i][g[i][j]]…… }
3. STL邻接矩阵存储的优化
(关于vector的用法,请见☟
Vector(动态数组)怎么用咧↓↓↓ - endl\n - 博客园 https://www.cnblogs.com/ljy-endl/p/11271899.html)
vector<int>g[101]; double w[101][101]; cin >> e; for (k = 1; k <= e; k++) { cin >> i >> j >> v; //读入两个顶点序号及权值 w[i][j]=w[j][i]=v; g[i].push_back(j);//对于不带权的图g[i][j]=1 g[j].push_back(i);//无向图的对称性, 有向图则不要! } 查询:O(e)//边数 for(int i=1;i<=n;i++) for(int j=0;j<g[i].size();j++) { 直接调用w[i][g[i][j]]…… }
4.数组模拟邻接表存储(!!!)(多用于稀疏图)
例:将下图用数组模拟邻接表存储
因为此图是无向图,所以还可以由输入得到:
然后再将上述数据整理一下,得到下表:
(i为第几条边,from指起点,to指终点,w指长度)
(注意不同颜色的数字和箭头)
将上表按照 从第几个顶点开始 的方式用下图存储
(数据处理完之后:head[第i个顶点]=i连接的最后一条边,然后又通过这一条边的nxt查询连接i顶点的下一条边,直到nxt=0为止)
(注意:是倒序存储,这样可以避免正序查找时重复遍历数组)
将上图所示的过程用代码写粗来就是下面的红色字体:
#include <iostream> using namespace std; const int maxn=1001,maxm=100001; struct Edge { int next; //下一条边的编号 int to; //这条边到达的点 int dis; //这条边的长度 }edge[maxm]; //也可以用to[maxm],dis[maxm],nxt[maxm]三个数组替代 int head[maxn],num_edge,n,m,u,v,d;//head[]表头,num_edge当前加入第几条边 void add_edge(int from,int to,int dis) //加入一条从from到to距离为dis的单向边 { edge[++num_edge].next=head[from]; edge[num_edge].to=to; edge[num_edge].dis=dis; head[from]=num_edge; } int main() { num_edge=0; scanf("%d %d",&n,&m); //读入点数和边数 for(int i=1;i<=m;i++) { scanf("%d %d %d",&u,&v,&d); //u、v之间有一条长度为d的边 add_edge(u,v,d); add_edge(v,u,d); //无向边多加一条反向的 } for(int j=1;j<=n;j++) for(int i=head[j];i!=0;i=edge[i].next) //遍历从点j开始的所有边 { //... } //... return 0; }