图的存储模板

图的存储

邻接矩阵

数据结构

设图的结点个数为 \(n\),定义 \(n\times n\) 的二维数组 \(g[N][N]\),其中 \(g[i][j]\) 表示结点 \(i\)\(j\) 的边权。

对于带权图,\(g[i][j]=\begin{cases}w &边(i, j)的权值 \\ +\infty &边(i,j)无直接连边\end{cases}\)

对于无权图,\(g[i][j]=\begin{cases}1 &i,j之间有连边 \\ 0 &i,j之间无连边\end{cases}\)

初始化

对于带权图,常用

memset(g, 0x3f, sizeof(g));

对于无权图,常用

memset(g, 0, sizeof(g));

或直接定义全局变量即可。

加边

加一条边 \((from, to, w)\),其中起点为 \(from\),终点为 \(to\),权值为 \(w\)(无权图权值为 \(1\) 即可)

对于有向图

g[from][to] = w;

对于无向图

g[from][to] = w;
g[to][from] = w;

遍历结点 s 的邻接点

对于带权图

const int INF = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
    if (g[s][i] < INF) {
        cout << i <<' ';
    }
}

对于无权图

for (int i = 1; i <= n; i++) {
    if (g[s][i] == 1) {
        cout << i <<' ';
    }
}

链氏前向星

数据结构

用数组模拟邻接表,需要一个表头数组 \(head[N]\),一个结构体数组 \(edge[M]\)

\(head[i]\) 表示以 \(i\) 为起点的第一条边在 \(edge\) 数组中的位置(下标)。

\(edge[i]\) 表示第 \(i\) 条边的信息。

// 注意两个数组的大小,head 大小为结点个数,edge 大小为边数,如果是无向图要两倍
int head[N];	// 表头数组
int tote;	// 当前加入的边的数量
struct EDGE {
    int to, w, nxt; //边的终点,权值,同一起点的下一条边的位置
} edge[M];

初始化

tot = 0;
//如果第一条边放在下标为 1 的位置,也可以初始化成 0,后面跑 tarjan 的时候从 0 开始存找反向边吏方便
memset(head, -1, sizeof(head));

加边

加一条边 \((from, to, w)\),其中起点为 \(from\),终点为 \(to\),权值为 \(w\)(无权图权值为 \(1\) 即可,或不要 \(w\) 这个成员变量)

// 加入的第一条边放到下标为 0 的位置,所以 head 数组要初始化成 -1
void addedge(int from, int to, int w) {
    edge[tote].to = to;
    edge[tote].w = w;
    edge[tote].nxt = head[from];
    head[from] = tote;
    tote++;
}

对于有向图

addedge(from, to, w);

对于无向图

addedge(from, to, w);
addedge(to, from, w);

遍历结点 s 的邻接点

对于带权图

cout << "s 的每条出边信息为:" << endl;
int to, w;
for (int i = head[s]; i != -1; i = edge[i].nxt) {
    to = edge[i].to;
    w = edge[i].w;
    cout << "终点:" << to << " 边权:" << w << endl;
}

vector 模拟邻接表

数据结构

用一个大小为 \(n\) 的 vector 数组 \(edge[N]\) 来维护每个结点的出边信息。

\(edge[i]\) 保存以 \(i\) 为起点的每条出边的信息(终点和权值),其中每个元素为一个 pair,如果需要更多信息,可以定义结构体。

对于带权图

struct EDGE {
    int to, w; // 边的终点to,边权w
};
vector<EDGE> edge[N]; // edge[i]存储i的所有出边信息

typedef pair<int, int> pii;
vector<pii> edge[N]; // 同上,只是用pair实现

对于无权图

vector<int> edge[N]; // edge[i]存储i的所有邻接点

初始化

对于单组测试数据,直接定义全局变量即可,对于多组测试数据,每次要清空 vector。

for (int i = 1; i <= n; i++) {	//n 为图中结点个数
    edge[i].clear();
}

加边

对于无权有向图,加入一条边 \((from, to)\)

edge[from].push_back(to);

对于无权无向图,加入一条边 \((from, to)\)

edge[from].push_back(to);
edge[to].push_back(from);

对于带权有向图,加入一条边 \((from, to, w)\)

edge[from].push_back(Node{to, w}); // 结构体实现
edge[from].push_back(make_pair(to, w)); // pair实现

// c++11加入了emplace_back()函数,可以略微提升时间和空间的效率
edge[from].emplace_back(Node{to, w}); // 结构体实现
edge[from].emplace_back(make_pair(to, w)); // pair实现

对于带权无向图,加入一条边 \((from, to, w)\)

// 结构体实现
edge[from].push_back(Node{to, w});
edge[to].push_back(Node{from, w});
// pair实现
edge[from].push_back(make_pair(to, w));
edge[to].push_back(make_pair(from, w));

// c++11加入了emplace_back()函数,可以略微提升时间和空间的效率
// 结构体实现
edge[from].emplace_back(Node{to, w});
edge[to].emplace_back(Node{from, w});
// pair实现
edge[from].emplace_back(make_pair(to, w));
edge[to].emplace_back(make_pair(from, w));

遍历结点 s 的邻接点

对于无权图

printf("s 的邻接点:");
for (const auto &to : edge[s]) {
    printf("%d ", to);
}

对于带权图

// 结构体实现
int to, w;
printf("s 的邻接点:");
for (const auto &e : edge[s]) {
    to = e.to;
    w = e.w;
    printf("结点:%d 边权:%d\n", to, w);
}

// pair实现
int to, w;
printf("s 的邻接点:");
for (const auto &e : edge[s]) {
    to = e.first;
    w = e.second;
    printf("结点:%d 边权:%d\n", to, w);
}
posted @ 2024-01-12 08:39  狂飙霹雳虎  阅读(99)  评论(1编辑  收藏  举报