求通用图结构的迭代式后序遍历算法及伪代码指导
通用图的迭代式后序遍历解决方案
嘿,我完全懂你的困扰——树的单栈/双栈后序遍历算法根本没法直接用到带环的图上,毕竟图里的回边、环会让栈的处理逻辑直接乱套。你已经搞定了递归版,那咱们就把它转换成能处理通用图的迭代版,完美匹配你要的结果。
核心思路:跟踪节点处理状态
递归版的本质是:标记节点为已访问 → 递归处理所有未访问的邻接点 → 处理完邻接点后把当前节点加入结果。要转成迭代,关键是用栈来模拟递归调用栈,同时给每个节点加个「是否已处理完邻接点」的状态标记——这样就能区分第一次遇到节点(需要先处理邻接点)和邻接点都处理完(可以加入结果)的两种情况。
伪代码实现
迭代式图后序遍历(起始节点 u): 初始化已访问集合 visited = 空集合 初始化栈 stack,压入 (u, 未处理) // 第二个元素标记节点状态 初始化结果列表 result = 空列表 当栈不为空时: 弹出栈顶元素 (current_node, status) 如果 status 是 已处理: 将 current_node 加入 result 继续下一次循环 如果 current_node 已在 visited 中: 继续下一次循环 将 current_node 加入 visited // 先把当前节点以「已处理」状态压回栈,等邻接点处理完再弹出它 将 (current_node, 已处理) 压入栈 // 逆序遍历邻接节点并压栈(栈是后进先出,逆序压入才能保证处理顺序和递归一致) 遍历 current_node 的所有出边对应的邻接节点 v(按逆序遍历): 如果 v 不在 visited 中: 将 (v, 未处理) 压入栈 返回 result
适配你的C++图模板的实现
结合你提供的tGraph模板结构,这里是对应的迭代版代码:
template<typename V, typename E> std::vector<V> tGraph<V, E>::IterativePostOrderSearch(const VertexType& start) const { std::set<VertexType> visited; // 栈存储节点 + 是否已处理完邻接点的标记 std::stack<std::pair<VertexType, bool>> nodeStack; std::vector<VertexType> result; nodeStack.push({start, false}); while (!nodeStack.empty()) { auto [current, isProcessed] = nodeStack.top(); nodeStack.pop(); // 邻接点都处理完了,加入结果 if (isProcessed) { result.push_back(current); continue; } // 已经访问过的节点直接跳过(避免环和重复处理) if (visited.find(current) != visited.end()) { continue; } // 标记为已访问,避免后续重复处理 visited.insert(current); // 先把当前节点以「已处理」状态压回栈,等邻接点处理完再处理它 nodeStack.push({current, true}); // 逆序遍历出边,保证和递归版的处理顺序一致(栈后进先出,逆序压入正序处理) EdgeSet edgesOut = outgoingEdgesOf(current); for (auto iter = edgesOut.rbegin(); iter != edgesOut.rend(); ++iter) { const VertexType& neighbor = iter->second.second; if (visited.find(neighbor) == visited.end()) { nodeStack.push({neighbor, false}); } } } return result; } // 对外调用接口,替换你原来的递归版实现 template<typename V, typename E> std::vector<V> tGraph<V, E>::postOrderList(const VertexType& v) const { return IterativePostOrderSearch(v); }
关键细节说明
- 状态标记的作用:
false表示第一次遇到节点,需要先处理它的所有邻接点;true表示邻接点都处理完毕,可以把节点加入结果列表——完美对应递归里「先递归子节点,再执行当前节点逻辑」的流程。 - 逆序压入邻接点:因为栈是后进先出结构,逆序遍历出边并压栈,能保证邻接点的处理顺序和递归版完全一致,这样你得到的结果会和递归版的
D、E、F、B、G、C、A完全匹配。 - 已访问集合:彻底解决图中环、回边的问题,每个节点只被标记一次,不会陷入无限循环。
内容的提问来源于stack exchange,提问作者tjgrant
相关产品推荐
相关产品推荐

