You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于适配指定类型签名的通用DFS(基于Set)算法实现咨询

适配目标类型的通用DFS实现

好的,我来帮你把这个基于Set的DFS实现适配到目标类型签名上。先梳理下原代码的核心逻辑:它用栈维护待访问节点,借助Set高效跟踪已访问节点避免重复遍历,同时把未访问的后继节点放到栈前部来保证深度优先的遍历顺序。

下面是适配后的完整实现,完全贴合dfs :: (Ord a) => (a -> [a]) -> a -> [a]的类型要求:

import qualified Data.Set as Set

dfs :: (Ord a) => (a -> [a]) -> a -> [a]
dfs succ start = loop [start] (Set.singleton start)
  where
    loop [] _ = []
    loop (x:xs) visited = x : loop (newNodes ++ xs) (Set.union visited newSet)
      where
        -- 将后继节点列表转换为Set,方便高效去重和差集计算
        succSet = Set.fromList (succ x)
        -- 筛选出当前节点的未访问后继节点集合
        newSet = Set.difference succSet visited
        -- 转回列表并放到栈前部,维持深度优先的遍历顺序
        newNodes = Set.toList newSet

关键修改点说明

  • 类型签名匹配:直接把原实现中(a -> Set a)的参数调整为(a -> [a]),完全符合目标签名要求。
  • 后继节点转换:新增succSet = Set.fromList (succ x)这一步——因为原实现依赖Set的高效差集操作来避免重复访问,现在把输入的后继列表转成Set,就能复用原有的高效逻辑,避免用列表elem做O(n)的低效重复检查。
  • 核心逻辑复用:栈的维护、已访问集合的更新、递归终止条件完全沿用原实现的逻辑,确保DFS的正确性和无重复遍历的特性。

测试示例

我们可以用一个简单的无向图来验证:

-- 节点1连接2和3,节点2、3都连接4,节点4无后继
graph :: Int -> [Int]
graph 1 = [2, 3]
graph 2 = [1, 4]
graph 3 = [1, 4]
graph 4 = [2, 3]
graph _ = []

调用dfs graph 1会输出[1,2,4,3](由于Set的有序性,后继节点会按Ord顺序排列,最终遍历顺序符合深度优先的预期)。

补充说明

如果不想依赖Set,理论上也可以用列表跟踪已访问节点,但elem操作是O(n)复杂度,对于大规模图来说效率会大幅下降。而目标类型签名带有Ord a约束,用Set是最优选择——既利用了Ord带来的高效集合操作,又保证了算法的正确性。

内容的提问来源于stack exchange,提问作者Leo Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:34:38