图的认识
组成
图主要是有一个二元组组成 G=<V,E>,V表示节点集,E表示边集,w表示一条边上的权值(自己定义)
方向
图分 有向图和无向图
有向图
所有边集都是有方向的,比如A->B,A可以到B,但是B到不了A;
无向图
所有边集都是没有方向的,比如A<–>B,A可以到B且B可以到A。
度数
无向图
无向图某点的度数指这个点连出的边数,无向图出度=入度
有向图
有向图出度不一定等于出度
图的存储
点非常好存,可边就不好存了,不过我们可以将边去转化为两个点。
邻接矩阵
存储原理
邻接矩阵用的是二维数组去存储图的边;
a [ i ] [ j ]表示节点i到节点j有一条边,权值为a[ i ] [ j ]
代码模板
//无向图
//定义
const int maxn=1e3+10;
int a[maxn][maxn];
//...
//加边
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",u,v);
a[u][v]=1;
a[v][u]=1;//根据题目要求,有向图不加这行代码
}
邻接表
存储原理
邻接表可根据对边的需求,进行开空间,类似队列;
代码模板
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,m;
//定义
vector< pair<int,int> >e[maxn];
int main(){
scanf("%d%d",&n,&m);
//加边
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u].push_back(make_pair(v,w));
e[v].push_back(make_pair(u,w));//根据题目要求,有向图不加这行代码
}
//调用操作
for(int i=1;i<=n;i++){
for(int j=0;j<e[i].size();j++){
//……
}
}
return 0;
}
链式前向星
存储原理
将与某点有关的边,存入一个链表中
代码模板
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,m,tot;
//定义
int head[maxn];
struct node {
int v,w,nxt;
}e[maxn];
void add(int u,int v,int w){
e[++tot].v=v;//更新边数记录新边弧头
e[tot].w=w;//记录权值
e[tot].nxt=head[u];//插入链表
head[u]=tot;//更新指针
}
int main(){
scanf("%d%d",&n,&m);
//加边
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
for(int i=head[u];i;i=e[i].nxt){
//......
}
return 0;
}
图的存储总结
-
邻接矩阵
空间复杂度O(n^2)
查边时间复杂度O(1) -
邻接表
空间复杂度O(n)
查边时间复杂度O(n)
空间不稳定
ps:邻接表空间一般会给你开两倍 -
链式前向星
空间复杂度O(n)
查边复杂度O(n)
空间稳定