struct ArcNode { // 边结点
int verIdx, weight;
ArcNode* next;
ArcNode(int verIdx, int weight, ArcNode* next) : verIdx(verIdx), weight(weight), next(next) {}
};
struct VNode { // 顶点结点
char vertex;
ArcNode* first;
};
struct AlGraph {
vector<VNode> VNodes;
};
struct MGraph {
vector<char> vertices; // 顶点集
vector<vector<int>> edges; // 邻接矩阵
};
写出从图的邻接表转化为邻接矩阵的算法。
MGraph adjList2Matrix(AlGraph& AG) {
int n = AG.VNodes.size();
MGraph MG;
vector<char> vertices;
vector<vector<int>> edges;
for (int i = 0; i < n; ++i) {
vertices.emplace_back(AG.VNodes[i].vertex);
}
for (int i = 0; i < n; ++i) {
ArcNode* arc = AG.VNodes[i].first;
while (arc != nullptr) {
edges[i][arc->verIdx] = arc->weight;
arc = arc->next;
}
}
return MG;
}
已知无向连通图 G 由顶点集 V 和 边集 E 组成,当 G 中度为奇数的结点个数为不大于 2 的偶数时,G 存在包含所有边且长度为 |E| 的路径(称为 EL 路径),假设图采用邻接矩阵存储。请设计算法,判断 G 是否存在 EL 路径。
bool isExistEL(MGraph& G) {
int n = G.vertices.size(), cnt = 0;
for (int i = 0; i < n; ++i) {
int deg = 0;
for (int j = 0; j < n; ++j) {
deg += G.edges[i][j] != 0;
}
cnt += deg % 2;
}
return cnt == 0 || cnt == 2;
}
设计一个算法,判断一个无向图 G 是否为一棵树。
bool dfs(MGraph& G, int preVex, int curVex, vector<bool>& visited) {
visited[curVex] = true;
for (int i = 0; i < G.vertices.size(); ++i) {
if (i == curVex) continue;
if (visited[i] && G.edges[curVex][i] != 0 && i != preVex) {
return false;
}
if (!visited[i] && G.edges[curVex][i] != 0) {
bool flag = dfs(G, curVex, i, visited);
if (!flag) return false;
}
}
return true;
}
bool isTree(MGraph& G) {
int n = G.vertices.size();
vector<bool> visited(n, false);
auto flag = dfs(G, -1, 0, visited);
if (!flag) return false;
for (int i = 0; i < n; ++i) {
if (!visited[i]) {
return false;
}
}
return true;
}
写出图的深度优先搜索 DFS 算法的非递归算法(图采用邻接表形式存储)。
void nonRecursiveDFS(AlGraph& G, int startIdx) {
vector<bool> visited(G.VNodes.size(), false);
stack<int> s;
s.emplace(startIdx);
visited[startIdx] = true;
while (!s.empty()) {
int curIdx = s.top();
s.pop();
cout << G.VNodes[curIdx].vertex << " ";
ArcNode* arc = G.VNodes[curIdx].first;
while (arc != nullptr) {
if (!visited[arc->verIdx]) {
s.emplace(arc->verIdx);
visited[arc->verIdx] = true;
}
arc = arc->next;
}
}
}
分别采用基于深度优先遍历和广度优先遍历算法判别以邻接表形式存储的有向图中是否存在由顶点 vi 到顶点 vj 的路径(i ≠ j)。注意,算法中涉及的图的基本操作必须在此存储结构上实现。
bool dfs(AlGraph& G, int vi, int vj, vector<bool>& visited) {
if (vi == vj) return true;
visited[vi] = true;
ArcNode* arc = G.VNodes[vi].first;
while (arc != nullptr) {
if (!visited[arc->verIdx] && dfs(G, arc->verIdx, vj, visited)) {
return true;
}
arc = arc->next;
}
return false;
}
bool hasPathDFS(AlGraph& G, int vi, int vj) {
vector<bool> visited(G.VNodes.size(), false);
return dfs(G, vi, vj, visited);
}
bool hasPathBFS(AlGraph& G, int vi, int vj) {
if (vi == vj) return true;
vector<bool> visited(G.VNodes.size(), false);
visited[vi] = true;
queue<int> q;
q.emplace(vi);
while (!q.empty()) {
int curIdx = q.front();
q.pop();
ArcNode* arc = G.VNodes[curIdx].first;
while (arc != nullptr) {
if (arc->verIdx == vj) {
return true;
}
if (!visited[arc->verIdx]) {
visited[arc->verIdx] = true;
q.emplace(arc->verIdx);
}
arc = arc->next;
}
}
return false;
}
假设图用邻接表表示,设计一个算法,输出从顶点 vi 到顶点 vj 的所有简单路径。
void printAllPathsDFS(AlGraph& graph, int vi, int vj, vector<bool>& visited, vector<int>& path) {
visited[vi] = true;
path.emplace_back(vi);
if (vi == vj) {
for (int i = 0; i < path.size(); i++) {
cout << path[i] << " ";
}
cout << endl;
}
else {
ArcNode* arc = graph.VNodes[vi].first;
while (arc != nullptr) {
if (!visited[arc->verIdx]) {
printAllPathsDFS(graph, arc->verIdx, vj, visited, path);
}
arc = arc->next;
}
}
visited[vi] = false;
path.pop_back();
}
void printAllPaths(AlGraph& G, int vi, int vj) {
vector<bool> visited(G.VNodes.size(), false);
vector<int> path;
printAllPathsDFS(G, vi, vj, visited, path);
}