算法【邻接矩阵、邻接表、链式前向星建图】
一般建图的三种方式
1.邻接矩阵(适合点的数量不多的图)
2.邻接表(最常用的方式)
3.链式前向星(空间要求严苛情况下使用。比赛必用,大厂笔试、面试不常用)
邻接矩阵自是不用多说,邻接表就是每个点后面跟一个存储着从这个点出发的连接的点,如果边带权值,就存储一个数组。下面着重讲解链式前向星建图。
在链式前向星建图中,有3个数组,分别是,head、next、to。head数组,下标为点的编号,一般从1开始,值代表从下标编号的点开始遍历的第一条边的编号,初始化为0,代表还没有边。next数组,下标为边的编号,一般从1开始,值代表遍历完这条边后下一条边的编号,如果为0代表没有了。to数组,下标为边的编号,一般从1开始,值代表这条边指向的点的编号。如果是带权图,那么新加一个weight数组,下标为边的编号,一般从1开始,值代表这条边的权值。当我们得到一条边的信息:出度节点i、入度节点j,这里建不带权图,我们会有一个cnt变量记录当前的边的编号,这时,由出度节点得到head[i],将next[cnt]赋值为head[i],然后把head[i]更新为cnt,最后将to[cnt]赋值为j。如果有权值,将weight[cnt]赋值为权值。最后cnt加1。将所有边更新完,图便建立完成。
下面给出三种建图方法的代码。代码如下。
#include <iostream>
#include <vector>
using namespace std;
// 点和边的数量
int m = 11;
int n = 21;
// 邻接矩阵建图 不带权图
int graph1[12][12];
void build1_1(vector<vector<int>>& edges){
for(int i = 0;i < n;++i){
graph1[edges[i][0]][edges[i][1]] = 1;
// graph1[edges[i][1]][edges[i][0]] = 1;
}
}
// 邻接矩阵建图 带权图
void build1_2(vector<vector<int>>& edges){
for(int i = 0;i < n;++i){
graph1[edges[i][0]][edges[i][1]] = edges[i][2];
// graph1[edges[i][1]][edges[i][0]] = edges[i][2];
}
}
// 邻接表建图 不带权图
vector<vector<int>> graph2_1;
void build2_1(vector<vector<int>>& edges){
vector<int> temp;
for(int i = 0;i <= m;++i){
graph2_1.push_back(temp);
}
for(int i = 0;i < n;++i){
graph2_1[edges[i][0]].push_back(edges[i][1]);
// graph2_1[edges[i][1]].push_back(edges[i][0]);
}
}
// 邻接表建图 带权图
vector<vector<vector<int>>> graph2_2;
void build2_2(vector<vector<int>>& edges){
vector<vector<int>> temp1;
vector<int> temp2;
for(int i = 0;i <= m;++i){
graph2_2.push_back(temp1);
}
for(int i = 0;i < n;++i){
temp2.push_back(edges[i][1]);
temp2.push_back(edges[i][2]);
graph2_2[edges[i][0]].push_back(temp2);
temp2.clear();
// temp2.push_back(edges[i][0]);
// temp2.push_back(edges[i][2]);
// graph2_2[edges[i][1]].push_back(temp2);
// temp2.clear();
}
}
// 链式前向星建图 不带权图
int Head[12] = {0};
int Next[22] = {0};
int To[22] = {0};
int cnt = 1;
void build3_1(vector<vector<int>>& edges){
for(int i = 0;i < n;++i){
Next[cnt] = Head[edges[i][0]];
Head[edges[i][0]] = cnt;
To[cnt] = edges[i][1];
++cnt;
// Next[cnt] = Head[edges[i][1]];
// Head[edges[i][1]] = cnt;
// To[cnt] = edges[i][0];
// ++cnt;
}
}
// 链式前向星建图 带权图
int Weight[22] = {0};
void build3_2(vector<vector<int>>& edges){
for(int i = 0;i < n;++i){
Next[cnt] = Head[edges[i][0]];
Head[edges[i][0]] = cnt;
To[cnt] = edges[i][1];
Weight[cnt] = edges[i][2];
++cnt;
// Next[cnt] = Head[edges[i][1]];
// Head[edges[i][1]] = cnt;
// To[cnt] = edges[i][0];
// Weight[cnt] = edges[i][2];
// ++cnt;
}
}
其中,点的编号和边的编号都是从1开始;默认建有向图,注释掉的代码是建无向图;m是点的数量,n是边的数量,当然这里这是做一个例子,具体情况具体修改即可。