图定义

邻接表

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;
}

是否存在EL路径

题目描述

已知无向连通图 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)。注意,算法中涉及的图的基本操作必须在此存储结构上实现。

解题代码

DFS

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);
}

BFS

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);
}