邻接矩阵/链式前向星/邻接表

以下我用比较通俗易懂的话来讲,所以可能不是很“专业”。

通俗来讲,邻接矩阵就是用一个二维数组来存储一个图的信息。 我们用a[i][j]来表示 点i---->j有一条边权值为a[i][j];如果i--->j无边则a[i][j]=0;

//输入u,v,w 表示有一条u指向v权值为w的单向边。
for (int i = 1; i <= m; ++i) {
    int u, v ,w;
    cin >> u >> v >> w;
    a[u][v] = w;
  }
//注意是单向边

这样就可以暴力储存全部信息了

复杂度

查询是否存在某条边:O(1)

遍历一个点的所有出边:O(n)

遍历整张图:O(N^2)

空间复杂度:O(N^2)

应用

邻接矩阵只适用于没有重边(或重边可以忽略)的情况。

其最显著的优点是可以 O(1) 查询一条边是否存在。

由于邻接矩阵在稀疏图上效率很低(尤其是在点数较多的图上,空间无法承受),所以一般只会在稠密图上使用邻接矩阵。

遍历一个点的所有出边也很简单:

for(i=1;i<=n;i++)
    if(a[u][i]!=0) {........}

但邻接矩阵会浪费很多空间。对于一些点数很大的图我们通常无法将图储存下来(比如一个点只连两条边 我们却要为它开长度为N的数组)

于是我们便可以用邻接表

对于邻接矩阵我们知道如果一个点只有几条边,我们便没必要为它浪费空间,只需要记录有用的边的信息再结合我们学过的 vector(可以动态开数组)的优点 便诞生了邻接表

使用一个支持动态增加元素的数据结构构成的数组,如 vector<int> adj[n + 1] 来存边,其中 adj[u] 存储的是点u的所有出边的相关信息(终点、边权等)。

vector<vector<int> > adj;
int main()
{
    adj.resize(n + 1);//先为每个点预留空间
    for (int i = 1; i <= m; ++i) 
    {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);//u这个点加一条边指向v
     }
}

这样我们就可以解决问题了。

接下来我们来介绍链式前向星

其实邻接表已经可以解决问题了但我们还是推荐用链式前向星:

内存: vector 是 c++STL 中的 动态连续存储线性表, vector在每次扩充容量时默认都会多申请2倍的空间
时间: STL的调用, 内部实现都导致 vector 是一个非常慢的结构

这样容易爆,所以来看链式前向星:

关于链式前向星,其实就是用一个链表将每条边的信息储存下来

我们定义h[N]数组表示 点 i最后一次加入的边的编号

用数组e[n]来储存第i条边的信息

struct node{
    int to,ne,value;
}e[N];
//当我们新加入一条边时  (u, v, w)u--->v 权值为w;
void add(int u,int v,int w)
{
    cnt++;//边的个数;
    e[cnt].to=v;
    e[cnt].ne=h[u];//e[cnt].ne=点u最后一次加边时边的编号,这样方便我们遍历一个点的所有出边
    e[cnt].value=w;
    h[u]=cnt;//更新点u
}

// 遍历 u 的出边
for (int i = h[u]; i!=0; i = e[i].ne)
  v=e[i].to;
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值