给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次。"遍历"即对结点进行某种操作

比如现在要找东西,假设有三个抽屉,东西在那个抽不清楚,现在要将其找到,广度优先遍历的做法是: 1.先将三个抽屉打开,在最外层找一遍 2.将每个抽屉中红色的盒子打开,再找一遍 3.将红色盒子中绿色盒子打开,再找一遍 直到找完所有的盒子,注意:每个盒子只能找一次,不能重复找

问题:如何防止节点被重复遍历
基本思路
void BFS(const V& src)
{
size_t srci = GetVertexIndex(src);
vector<bool> visited;
visited.resize(_vertexs.size(), false);
queue<int> q;
q.push(srci);
visited[srci] = true;
while (!q.empty())
{
int front = q.front();
q.pop();
cout << front << ":" << _vertexs[front] << endl;
//把front的邻接顶点入队列
for (int i = 0; i < _vertexs.size(); i++)
{
if (_matrix[front][i] != MAX_W && visited[i] == false)
{
visited[i] = true;
q.push(i);
}
}
}
}A -- B -- C
| |
D -- EA: B, D
B: A, C, E
C: B
D: A, E
E: B, Dq = [A]visited = {A}A,访问 A。A 的邻居 B 和 D: B 和 D 加入队列:q = [B, D]B 和 D 为已访问:visited = {A, B, D}B,访问 B。B 的邻居 A、C、E: A 已访问,跳过。C 和 E 加入队列:q = [D, C, E]C 和 E 为已访问:visited = {A, B, D, C, E}D,访问 D。D 的邻居 A、E: A 和 E 已访问,跳过。C,访问 C。C 的邻居 B: B 已访问,跳过。E,访问 E。E 的邻居 B、D: B 和 D 已访问,跳过。遍历顺序:
A -> B -> D -> C -> E
关键点
A 时会发现 B,然后访问 B 时会发现 A,没有标记的话会导致无限循环。,其中
是顶点数,
是边数。
,遍历每个顶点的所有邻居需要
。
,因为需要检查矩阵中的每个元素。
。

比如现在要找东西,假设有三个抽屉,东西在那个抽屉不清楚,现在 要将其找到,广度优先遍历的做法是:
深度优先遍历:将一个抽屉一次性遍历完(包括该抽屉中包含的小盒 子),再去递归遍历其他盒子

void _DFS(size_t srci,vector<bool> & visited)
{
cout << srci << ":" << _vertexs[src] << " ";
visited[srci] = true;
for (int i = 0; i < _vertexs.size(); i++)
{
if (_matrix[srci][i] != MAX_W && visited[i] == false)
{
_DFS(i, visited);
}
}
}
void DFS(const V& src)
{
size_t srci = GetVertexIndex(src);
vector<bool> visited(_vertexs.size(), false);
_DFS(src, visited);
}深度优先遍历的特点
基本思路
1. 初始化
2. 递归实现
3. 使用显式栈
非递归实现(使用栈)
void DFS(Graph& graph, const V& start) {
stack<V> s; // 栈用于存储待访问的顶点
unordered_set<V> visited; // 标记已访问顶点
s.push(start); // 将起始顶点压入栈
while (!s.empty()) {
V current = s.top(); // 取出栈顶顶点
s.pop();
if (visited.find(current) == visited.end()) {
// 标记当前顶点为已访问
visited.insert(current);
// 处理当前顶点(例如打印)
cout << current << " ";
// 将未访问的邻居压入栈
for (const auto& neighbor : graph.GetNeighbors(current)) {
if (visited.find(neighbor) == visited.end()) {
s.push(neighbor);
}
}
}
}
}详细过程与示例
假设图如下(无向图):
A -- B -- C
| |
D -- E邻接表表示:
A: B, D
B: A, C, E
C: B
D: A, E
E: B, D从顶点 A 开始的深度优先遍历
初始状态:
visited = {}遍历过程:
A,标记为已访问:visited = {A}A 的邻居中选择未访问的 B,递归进入顶点 B: B,标记为已访问:visited = {A, B}B 的邻居中选择未访问的 C,递归进入顶点 C: C,标记为已访问:visited = {A, B, C}C 的邻居 B 已访问,递归返回到顶点 B。B,继续访问其未访问的邻居 E,递归进入顶点 E: E,标记为已访问:visited = {A, B, C, E}E 的邻居中选择未访问的 D,递归进入顶点 D: D,标记为已访问:visited = {A, B, C, D, E}D 的邻居 A、E 均已访问,递归返回到顶点 E。E,无更多未访问的邻居。B,无更多未访问的邻居。A,继续访问其未访问的邻居 D: D 已访问,跳过。最终结果:A -> B -> C -> E -> D
初始状态:
s = [A]visited = {}遍历过程:
A,访问 A:visited = {A},将邻居 B 和 D 压入栈:
s = [B, D]D,访问 D:visited = {A, D},将邻居 E 压入栈:
s = [B, E]E,访问 E:visited = {A, D, E},将邻居 B 压入栈:
s = [B, B]B,访问 B:visited = {A, D, E, B},将邻居 C 压入栈:
s = [B, C]C,访问 C:visited = {A, D, E, B, C}。
s = [B]B,发现已访问,跳过。
最终结果:A -> D -> E -> B -> C
深度优先遍历的时间和空间复杂度
,其中
是顶点数,
是边数。
,因为需要检查矩阵中的每一项。
应用**