图的保存
边的表示
// 适用于一般情况的边的表示
// 根据不同的情况有不同的变体
struct Edge {
int from, to, cost;
}
邻接矩阵
d[from][to]=cost
最简单的方式,适用于密集图
缺点:内存消耗是O(V2),点太多会存不下
静态邻接表
貌似有很多称呼,我觉得还是这个比较贴切。
优势:
直接访问从某个节点出发的所有弧,效率高。
可以直接通过id(下标)来访问某条边。
节省内存。
Edge E[MaxE], tot;
int head[MaxV], next[MaxE];
void init() {
memset(head, -1, sizeof(head));
tot = 0;
}
void add_edge(int from, int to, cost) {
next[tot] = head[from];
head[from] = tot;
E[tot++] = Edge(from, to, cost);
}
// 遍历从u出发的所有弧
void foo(int u) {
for (int i = head[u];i != -1;i = next[i]) {
// ...
}
}
使用vector的邻接表
根据个人习惯有很多变体,列举一下我常用的
优点:
相比静态内存的邻接矩阵,往往可以减少很多内存消耗。
同时比邻接表易于coding。
缺点:访问速度较慢。
第一种
// 直接存放边
vector<Edge> G[MaxV];
void add_edge(int from, int to, int cost) {
G[from].push_back( Edge(from, to, cost) );
}
// 访问
void foo(int u) {
int sz = G[u].size();
for (int i=0;i<sz;++i) {
Edge &e = G[u][i];
// ...
}
}
第二种
我更偏好这一种,很多时候会更方便。
vector<Edge> E;
vector<int> G[MaxV]; // 图中只保存边的id
void add_edge(int from, int to, int cost) {
G[from].push_back(E.size());
E.push_back( Edge(from, to, cost) );
}
// 访问
void foo(int u) {
int sz = G[u].size();
for (int i=0;i<sz;++i) {
Edge &e = E[G[u][i]];
// ...
}
}
动态内存的邻接表
编程复杂度高,容易出错。。
struct node{
int to, cost;
node *next;
node (int to, int cost) :to(to), cost(cost){
next = NULL;
}
};
class Graph {
node **G;
int MaxV;
void init(int V) {
MaxV = V;
G = new node*[V];
}
void add_edge(int from, int to, int cost) {
node * p = new node(to, cost);
p->next = G[from];
G[from] = p;
}
void clear() {
for (int i=0;i<MaxV;++i) if (G[i] != NULL) {
node *p = G[i];
while (p) {
node *tmp = p->next;
delete p;
p = tmp;
}
}
delete [] G;
}
};

1万+

被折叠的 条评论
为什么被折叠?



