图论-图的存储

图的存储

从这里查看更详细的教程
图片和部分思路来源于 算法学习笔记(3)存图
最简单朴素的存储方式:

通过二维数组实现图的存储
若点 i 与点 j有连接

则graph[i][j]=1

在这里插入图片描述

int graph[100][100];
int main()
{
	int u,v;
	cin>>u>>v;
	gragp[u][v]=1; 
	//graph[v][u]=1; 无向图 
}

对带有有权重的图 只需要将1改为存储权重w即可

int graph[100][100];
int main()
{
	int u,v,w;
	cin>>u>>v>>w;
	gragp[u][v]=w; 
	//graph[v][u]=w; 无向图 
}

但缺点显而易见 在图很小但是节点数较大时
需要耗费大量的空间来进行存储
在数据系数的时候绝大部分空间是被浪费了

于是很快你就能想到一个更好的解决方案:
(通过链表来实现图的存储)

但是手写链表却并不是一件容易的事情(至少对我这个蒟蒻而言是这样的)
但貌似有个list的stl可以用用(后期补上)

所以在此强烈推荐std::vector

开始之前首先建立一个Edge结构体 用来存储端点和权值

struct Edge{
	int to,w;//to代表通向的端点   w代表边的权重
};

先说优点
STL里的vector容器,作为动态数组,既拥有链表节省内存的优点,但又可以以类似数组的方式访问,而且写法也很简便。(引用自算法学习笔记(3))

vector<Edge> bian[100];
void add(int from,int to ,int w)
{
	bian[from].push_back(edge{to,w});
}
int main()
{
	int n;
	cin>>n;//循环读入n组数据
	int x,y,z;
	for(int i=1;i<=n;i++)
	{
		cin>>x>>y>>z;
		add(x,y,z);//建图
		
	}

这样经过遍历 你就能得到一张全新的关系图(一张链式存储的关系图)

算法学习笔记3

遍历方法可以使用常规的数组遍历方法 遍历二维数组 也可以通过auto 来遍历

	for(int j=0;j<=5;j++){
		for(int i=0;i<bian[j].size();i++)
				{
					cout<<bian[j][i].to<<" ";
				}
		cout<<endl;
	}

链式前向星

(貌似是一个更简单但是写起来复杂的高端存储方式?//至少在我还没理解这个过程的情况下 我觉得前向星还是蛮复杂的)

看这篇文章吧 写的稍微清晰一点 深度理解链式前向星
当然也可以看看原作者

链式前向星其实就是静态建立的邻接表,时间效率为O(m),空间效率也为O(m)。遍历效率也为O(m) 引用自大佬文章

先来一组数据

1 2
2 3
3 4
1 3
4 1
1 5
4 5

构建的图如下
在这里插入图片描述
首先先介绍前向星

前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,

并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.

说明几个数组的意义

用len[i]来记录所有以i为起点的边在数组中的存储长度.
用head[i]记录以i为边集在数组中的第一个存储位置.

编号:     1      2      3      4      5      6      7
起点u:    1      1      1      2      3      4      4
终点v:    2      3      5      3      4      1      5

而后得到下面的head和len

head[1] = 1      len[1] = 3
head[2] = 4      len[2] = 1 
head[3] = 5      len[3] = 1
head[4] = 6      len[4] = 2

如果用链式前向星,就可以避免排序.

我们建立边结构体为:
引用自 深度理解链式前向星

struct Edge

{

 int next;

 int to;

 int w;

};

其中edge[i].to表示第i条边的终点
edge[i].next表示与第i条边同起点的下一条边的存储位置
edge[i].w为边权值.
另外还有一个数组head[],它是用来表示以i为起点的第一条边存储的位置,
实际上你会发现这里的第一条边存储的位置其实在以i为起点的所有边的最后输入的那个编号.

head[]数组一般初始化为-1,对于加边的add函数是这样的:

void add(int u,int v,int w)
{
    edge[cnt].w = w;
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

其实手动模拟一下可能会对更容易理解链式前向星
Oiwiki上的参考代码

// head[u] 和 cnt 的初始值都为 -1
void add(int u, int v) {
  nxt[++cnt] = head[u];  // 当前边的后继
  head[u] = cnt;         // 起点 u 的第一条边
  to[cnt] = v;           // 当前边的终点
}

// 遍历 u 的出边
for (int i = head[u]; ~i; i = nxt[i]) {  // ~i 表示 i != -1
  int v = to[i];
}

链式前向星的模板

#include <iostream>
#include <vector>

using namespace std;

int n, m;
vector<bool> vis;
vector<int> head, nxt, to;

void add(int u, int v) {
  nxt.push_back(head[u]);
  head[u] = to.size();
  to.push_back(v);
}

bool find_edge(int u, int v) {
  for (int i = head[u]; ~i; i = nxt[i]) {  // ~i 表示 i != -1
    if (to[i] == v) {
      return true;
    }
  }
  return false;
}

void dfs(int u) {
  if (vis[u]) return;
  vis[u] = true;
  for (int i = head[u]; ~i; i = nxt[i]) dfs(to[i]);
}

int main() {
  cin >> n >> m;

  vis.resize(n + 1, false);
  head.resize(n + 1, -1);

  for (int i = 1; i <= m; ++i) {
    int u, v;
    cin >> u >> v;
    add(u, v);
  }

  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值