概念:
链式前向星(Chained Forward Star)是一种常用的图存储和遍历的数据结构,用于表示稀疏图,实际上就是一种用链表实现的邻接表,以边为基本单位,保存以每个点作为起点的边。其中链表通过数组来模拟,使用头插法维护。
实现:
为了更加方便地理解链式前向星,我们对一下这个有向图进行分析。
一般情况下,我们描述一张图,采用from to weight,表示从from到to两个点之间的边权值weight
上图中描述则对应如下
from | to | weight |
1 | 2 | 1 |
2 | 3 | 3 |
3 | 4 | 5 |
1 | 3 | 4 |
1 | 4 | 2 |
一般见到的链式前向星使用4个数组进行描述,如下所示:
但是不利于初学者学习,为了便于理解,其中to,w,nex数组都是边的属性,因此将其简化为数组来表示:
使用add函数对链式前向星进行更新;
最终产生的邻接表如下所示:
完整代码如下:
#include "iostream"
#include "cstring"
using namespace std;
const int N = 1e4;
struct edge {
int w;
int to;
int nxt;
} edges[N];
int head[N];
int cnt = 1; //cnt为新加入边的序号
void add(int a, int b, int c) {
edges[cnt].to = b; //记录每条边的终点
edges[cnt].w = c; //记录每条边的权重
edges[cnt].nxt = head[a]; //以同一点a为起点的最新加入的边指向上一次最新加入的边(即头插法)
head[a] = cnt++; //h[a]即表示以点a为起点的最新边的序号
}
int main() {
memset(head, -1, sizeof head);
int n = 5;
while (n--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
//遍历该邻接表
for (int i = 1; i <= 5; i++) {
cout << i << " " << head[i] << " ";
//遍历以点i为起点的所有边
for (int j = head[i]; j != -1; j = edges[j].nxt) {
printf("{id: %d, to:%d, w =%d, nxt:%d} ", j, edges[j].to, edges[j].w, edges[j].nxt);
}
cout << endl;
}
}
链式前向星的应用:
示例1:采用堆优化的Dijkstra算法实现单源最短路径,题目描述如下所示:
实现代码:
#include "queue"
#include "iostream"
#include "cstring"
#include "vector"
#include "unordered_map"
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int dist[N];
bool state[N];
int head[N];
int cnt = 1;
int n,m;
struct edge {
int w;
int to;
int nxt;
} edges[N];
void add(int a, int b, int c) {
edges[cnt].to = b; //记录每条边的终点
edges[cnt].w = c; //记录每条边的权重
edges[cnt].nxt = head[a]; //以同一点a为起点的最新加入的边指向上一次最新加入的边(即头插法)
head[a] = cnt++; //h[a]即表示以点a为起点的最新边的序号
}
struct CompareSecond {
bool operator()(PII &a, PII &b) {
return a.second > b.second;
}
};
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, CompareSecond> heap;
heap.emplace(1, 0);
while (!heap.empty()) {
auto minP = heap.top();
heap.pop();
int vertex = minP.first; //获取当前临时距离最小点
int distance = minP.second; //获取最小临时距离
if (state[vertex]) continue;
state[vertex] = true;
for (int i = head[vertex]; i != -1; i = edges[i].nxt) {
//在邻接表中搜索vertex能够到达的点,更新所有能更新的点的临时距离
int j = edges[i].to; //所有vertex能够到达的点
if (dist[j] > distance + edges[i].w) {
dist[j] = distance + edges[i].w;
heap.emplace(j, dist[j]);
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main() {
cin >> n >> m;
memset(head, -1, sizeof head);
while (m--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
cout << dijkstra();
}