如何在功能上生成的树广度优先。 (哈斯克尔)
-
27-09-2019 - |
题
说我有以下的Haskell树类型,其中“状态”是一个简单的包装:
data Tree a = Branch (State a) [Tree a]
| Leaf (State a)
deriving (Eq, Show)
我也有一个函数“扩大::树一 - >树一个”这需要的叶节点, 并扩展成一个分支,或者需要一个分支,并返回其不变。此树类型代表N叉检索树。
搜索深度优先是一种浪费,并作为搜索空间显然是无限的,我可以很容易地保持在与利用展开所有树的叶子节点上的扩大搜索空间,并且意外丢失的机会目标状态是巨大的......因此,唯一的解决办法是广度优先搜索,实现相当不错的了的此处,这将找到解决方案,如果它的存在。
我的想什么的产生,虽然是树遍历的最多的寻找解决方案。 这是一个问题,因为我只知道如何做到这一点的深度优先,这可以通过完成简单地称为在第一个子节点一次又一次地“扩大”功能...直到一个目标状态被发现。 (这真的不产生任何其他那么真不舒服列表。)
任何人都可以给我是否有可能以一个体面的复杂性上如何做到这一点的任何提示(或整个算法),或评价呢? (或者对这个任何来源,因为我发现相当少。)
解决方案
你有没有看着克里斯·奥卡萨基的 “广度优先编号:教训从一个小练习在算法设计” ?所述Data.Tree
模块包括使用算法名为unfoldTreeM_BF
一元树构建器适于从该纸。
下面是我认为对应于自己在做什么的例子:
假设我想,所有的留守儿童是家长串加上搜索字符串的无限二叉树“一”,右孩子是父母加“BB”。我可以用unfoldTreeM_BF
搜索树广度优先,返回搜索树高达解决方案:
import Control.Monad.State
import Data.Tree
children :: String -> [String]
children x = [x ++ "a", x ++ "bb"]
expand query x = do
found <- get
if found
then return (x, [])
else do
let (before, after) = break (==query) $ children x
if null after
then return (x, before)
else do
put True
return (x, before ++ [head after])
searchBF query = (evalState $ unfoldTreeM_BF (expand query) []) False
printSearchBF = drawTree . searchBF
这是不是非常漂亮,但它的工作原理。如果我搜索“AABB”我知道正是我想要的:
|
+- a
| |
| +- aa
| | |
| | +- aaa
| | |
| | `- aabb
| |
| `- abb
|
`- bb
|
+- bba
|
`- bbbb
如果这是那种你所描述的东西,它不应该是很难为你的树类型相适应。
更新:这是expand
的做免费的版本,如果你到这种事情:
expand q x = liftM ((,) x) $ get >>= expandChildren
where
checkChildren (before, []) = return before
checkChildren (before, t:_) = put True >> return (before ++ [t])
expandChildren True = return []
expandChildren _ = checkChildren $ break (==q) $ children x
(感谢camccann用于催促我远离旧的控制结构的习惯,希望这个版本是更可接受。)
其他提示
我很好奇,为什么你需要在所有的expand
功能 - 为什么不能简单地构建整个树递归和执行任何搜索您想要的吗?
如果您是为了跟踪哪些节点通过搜索审查,因为你去似乎更简单,甚至是第二树结构建立一个列表使用expand
。
下面是一个简单的例子,仅仅返回找到的第一个结果是,除去了杂散Leaf
构造:
data State a = State { getState :: a } deriving (Eq, Show)
data Tree a = Branch {
state :: State a,
children :: [Tree a]
} deriving (Eq, Show)
breadth ts = map (getState . state) ts ++ breadth (concatMap children ts)
search f t = head $ filter f (breadth [t])
mkTree n = Branch (State n) (map mkTree [n, 2*n .. n*n])
testTree = mkTree 2
想出来在GHCI:
> search (== 24) testTree
24
有关此相反,这里有一个幼稚深度优先搜索:
depth (Branch (State x) ts) = x : (concatMap depth ts)
dSearch f t = head $ filter f (depth t)
...这当然失败(== 24)
搜索时,因为最左边的分支是无尽的系列2S的终止。