C++ 链式前向星
链式前向星结合了数组和链表的特性,通过数组来存储边的信息,通过链表来连接各个顶点.
链式前向星的边的添加:
function addEdge(from, to, weight)
e = {to, weight, head[from]} //第一个参数是这条边的终点,第二个参数是权重,第三个是这条边 // 在边链表中下一条边的下标
edges.append(e)
head[from] = size(edges) - 1
end
链式前向星代码框架
#include<iostream>
#include<vector>
using namespace std;//边的起点是不用存储的
//因为所有起点相同的边,会被一个链表连接起来
template<typename T>
struct Edge {int to;T weight;int next;
};template<class T>
class Graph {
private:vector<Edge<T>> m_edges;vector<int> m_head;public:Graph(int n);void addEdge(int from, int to, T weight);void printEdges();
};template<class T>
Graph<T>::Graph(int n)
{m_edges.clear();m_head.resize(n, -1); //m_head 为一个值全为-1的数组}template<class T>
void Graph<T>::addEdge(int from, int to, T weight)
{m_edges.push_back(Edge<T>{to, weight, m_head[from]});m_head[from] = (int)m_edges.size() - 1;}template<class T>
void Graph<T>::printEdges()
{int n = m_head.size();for (int i = 0; i < n; ++i) {cout << i << ":";for (int e = m_head[i]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;T w = m_edges[e].weight;cout << "(" << v << "," << w << ")";}cout << endl;}
}int main() {int n, m;cin >> n >> m;Graph<int> g(n);while (m--) {int a, b, c;cin >> a >> b >> c;g.addEdge(a, b, c);}g.printEdges();return 0;
}代码练习 金苹果群岛的建设 蓝桥云课 代码见下
#include<iostream>
#include<vector>
using namespace std;//边的起点是不用存储的
//因为所有起点相同的边,会被一个链表连接起来
template<typename T>
struct Edge {int to;T weight;int next;
};template<class T>
class Graph {
private:vector<Edge<T>> m_edges;vector<int> m_head;int m_count;vector<int> m_colors; // m_color[i]代表每一个染色后岛屿,一开始没染色的时候是-1void dfs(int u); // 从u出发,将u和周边的岛屿进行染色public:Graph(int n);void addEdge(int from, int to, T weight);void printEdges();int countConnectedBlock(); // 利用这个函数,统计一张图中,连通分量的个数
};template<class T>
void Graph<T>::dfs(int u)
{if (m_colors[u] != -1) {return;}m_colors[u] = m_count;for (int e = m_head[u]; e != -1; e = m_edges[e].next) {dfs(m_edges[e].to);}
}template<class T>
Graph<T>::Graph(int n)
{m_edges.clear();m_head.resize(n, -1); //m_head 为一个值全为-1的数组}template<class T>
void Graph<T>::addEdge(int from, int to, T weight)
{m_edges.push_back(Edge<T>{to, weight, m_head[from]});m_head[from] = (int)m_edges.size() - 1;}template<class T>
void Graph<T>::printEdges()
{int n = m_head.size();for (int i = 0; i < n; ++i) {cout << i << ":";for (int e = m_head[i]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;T w = m_edges[e].weight;cout << "(" << v << "," << w << ")";}cout << endl;}
}template<class T>
int Graph<T>::countConnectedBlock()
{int n = (int)m_head.size();m_count = 0;m_colors.resize(n, -1);for (int i = 0; i < n; ++i) {if (m_colors[i] == -1) {dfs(i);m_count++;}}return m_count;
}int main() {int n, m;cin >> n >> m;Graph<int> g(n);while (m--) {int a, b;cin >> a >> b;--a, --b;g.addEdge(a, b, 0);g.addEdge(b, a, 0);}cout << g.countConnectedBlock() - 1 << endl;return 0;
}代码练习 2 图的遍历 对应洛谷 代码见下
#include<iostream>
#include<vector>
using namespace std;//边的起点是不用存储的
//因为所有起点相同的边,会被一个链表连接起来
template<typename T>
struct Edge {int to;T weight;int next;
};template<class T>
class Graph {
private:vector<Edge<T>> m_edges;vector<int> m_head;vector<bool> m_visited; // m_visited[i] 为true的时候,代表访问过了,否则就是没有访问。void dfs(int u, int& ans);// u代表从单前点开始访问,ans代表访问过程中编号的最大值public:Graph(int n);void addEdge(int from, int to, T weight);void printEdges();int caculateColor(int u); //代表从u出发,能够访问到最大节点的编号
};template<class T>
void Graph<T>::dfs(int u, int& ans)
{if (m_visited[u]) {return;}m_visited[u] = true;if (u > ans) {ans = u;}for (int e = m_head[u]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;dfs(v, ans);}
}template<class T>
Graph<T>::Graph(int n)
{m_edges.clear();m_head.resize(n, -1); //m_head 为一个值全为-1的数组}template<class T>
void Graph<T>::addEdge(int from, int to, T weight)
{m_edges.push_back(Edge<T>{to, weight, m_head[from]});m_head[from] = (int)m_edges.size() - 1;}template<class T>
void Graph<T>::printEdges()
{int n = m_head.size();for (int i = 0; i < n; ++i) {cout << i << ":";for (int e = m_head[i]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;T w = m_edges[e].weight;cout << "(" << v << "," << w << ")";}cout << endl;}
}template<class T>
int Graph<T>::caculateColor(int u)
{int n = m_head.size();m_visited.resize(n);for (int i = 0; i < n; ++i) {m_visited[i] = false;}int ans = u;dfs(u, ans);return ans;
}int main() {int n, m;cin >> n >> m;Graph<int> g(n);while (m--) {int a, b;cin >> a >> b;--a, --b;g.addEdge(a, b, 0);}for (int i = 0; i < n; ++i) {cout << g.caculateColor(i) + 1 << " ";}cout << endl;return 0;
}代码练习 3 图的遍历(进阶版),对应洛谷
#include<iostream>
#include<vector>
using namespace std;//边的起点是不用存储的
//因为所有起点相同的边,会被一个链表连接起来
template<typename T>
struct Edge {int to;T weight;int next;
};template<class T>
class Graph {
private:vector<Edge<T>> m_edges;vector<int> m_head;vector<int> m_colors;void dfs(int u, int color);public:Graph(int n);void addEdge(int from, int to, T weight);void printEdges();void caculateColor();int getColor(int v) const;
};template<class T>
void Graph<T>::dfs(int u, int color)
{if (m_colors[u] != -1) {return;}m_colors[u] = color;for (int e = m_head[u]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;dfs(v, color);}
}template<class T>
Graph<T>::Graph(int n)
{m_edges.clear();m_head.resize(n, -1); //m_head 为一个值全为-1的数组}template<class T>
void Graph<T>::addEdge(int from, int to, T weight)
{m_edges.push_back(Edge<T>{to, weight, m_head[from]});m_head[from] = (int)m_edges.size() - 1;}template<class T>
void Graph<T>::printEdges()
{int n = m_head.size();for (int i = 0; i < n; ++i) {cout << i << ":";for (int e = m_head[i]; e != -1; e = m_edges[e].next) {int v = m_edges[e].to;T w = m_edges[e].weight;cout << "(" << v << "," << w << ")";}cout << endl;}
}template<class T>
void Graph<T>::caculateColor()
{int n = (int)m_head.size();m_colors.resize(n, -1);for (int i = n - 1; i >= 0; --i) {if (m_colors[i] == -1) {dfs(i, i);}}
}template<class T>
int Graph<T>::getColor(int v) const
{return m_colors[v];
}int main() {int n, m;cin >> n >> m;Graph<int> g(n);while (m--) {int a, b;cin >> a >> b;--a, --b;g.addEdge(b, a, 0);}g.caculateColor();for (int i = 0; i < n; ++i) {cout << g.getColor(i) + 1 << " ";}cout << endl;return 0;
}