假设我有以下 Haskell 树类型,其中“State”是一个简单的包装器:
data Tree a = Branch (State a) [Tree a]
| Leaf (State a)
deriving (Eq, Show)
我还有一个函数“expand :: Tree a -> Tree a”,它接受一个叶节点,
并将其扩展为一个分支,或者获取一个分支并将其原样返回。该树类型表示 N 元搜索树。
深度优先搜索是一种浪费,因为搜索空间显然是无限的,因为我可以通过对所有树的叶节点使用扩展来轻松地继续扩展搜索空间,并且有可能意外错过目标状态是巨大的...因此唯一的解决方案是广度优先搜索,在 此处,如果存在解决方案,它将找到解决方案。
不过,我想要生成的是遍历树直到找到解决方案。
这是一个问题,因为我只知道如何执行深度优先,这可以通过简单地在第一个子节点上一次又一次地调用“扩展”函数来完成......直到找到目标状态。 (除了一个非常不舒服的列表之外,这实际上不会生成任何东西。)
任何人都可以给我任何关于如何做到这一点(或整个算法)的提示,或者判断它是否可能具有相当的复杂性? (或者任何有关这方面的资料,因为我发现的很少。)
Say I have the following Haskell tree type, where "State" is a simple wrapper:
data Tree a = Branch (State a) [Tree a]
| Leaf (State a)
deriving (Eq, Show)
I also have a function "expand :: Tree a -> Tree a" which takes a leaf node,
and expands it into a branch, or takes a branch and returns it unaltered. This tree type represents an N-ary search-tree.
Searching depth-first is a waste, as the search-space is obviously infinite, as I can easily keep on expanding the search-space with the use of expand on all the tree's leaf nodes, and the chances of accidentally missing the goal-state is huge... thus the only solution is a breadth-first search, implemented pretty decent over here, which will find the solution if it's there.
What I want to generate, though, is the tree traversed up to finding the solution.
This is a problem because I only know how to do this depth-first, which could be done by simply called the "expand" function again and again upon the first child node... until a goal-state is found. (This would really not generate anything other then a really uncomfortable list.)
Could anyone give me any hints on how to do this (or an entire algorithm), or a verdict on whether or not it's possible with a decent complexity? (Or any sources on this, because I found rather few.)
发布评论
评论(2)
你看过克里斯·冈崎的“Breadth-第一次编号:算法设计小练习的经验教训”?
Data.Tree
模块包括一个名为unfoldTreeM_BF
的一元树构建器,它使用改编自该论文的算法。这是一个我认为与您正在做的事情相对应的示例:
假设我想搜索字符串的无限二叉树,其中所有左子节点都是父字符串加“a”,右子节点是父字符串加“bb” 。我可以使用
unfoldTreeM_BF
广度优先搜索树并将搜索到的树返回到解决方案:这不是非常漂亮,但它有效。如果我搜索“aabb”,我就会得到我想要的东西:
如果这是您所描述的类型,那么适应您的树类型应该不难。
更新:这是
expand
的免费版本,以防你对这种事情感兴趣:(感谢 camccann 促使我摆脱旧的控制结构习惯。我希望这个版本更容易被接受.)
Have you looked at Chris Okasaki's "Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design"? The
Data.Tree
module includes a monadic tree builder namedunfoldTreeM_BF
that uses an algorithm adapted from that paper.Here's an example that I think corresponds to what you're doing:
Suppose I want to search an infinite binary tree of strings where all the left children are the parent string plus "a", and the right children are the parent plus "bb". I could use
unfoldTreeM_BF
to search the tree breadth-first and return the searched tree up to the solution:This isn't terribly pretty, but it works. If I search for "aabb" I get exactly what I want:
If this is the kind of thing you're describing, it shouldn't be hard to adapt for your tree type.
UPDATE: Here's a do-free version of
expand
, in case you're into this kind of thing:(Thanks to camccann for prodding me away from old control structure habits. I hope this version is more acceptable.)
我很好奇为什么你需要
expand
函数——为什么不简单地递归地构造整个树并执行你想要的任何搜索?如果您使用
expand
来跟踪搜索检查的节点,那么构建一个列表似乎更简单,甚至是第二个树结构。下面是一个简单的示例,仅返回找到的第一个结果,并删除了虚假的
Leaf
构造函数:在 GHCi 中尝试:
作为对比,这是一个简单的深度优先搜索:
...当然使用
(== 24)
搜索时无法终止,因为最左边的分支是无穷无尽的 2 序列。I'm curious why you need the
expand
function at all--why not simply construct the entire tree recursively and perform whatever search you want?If you're using
expand
in order to track which nodes are examined by the search, building a list as you go seems simpler, or even a second tree structure.Here's a quick example that just returns the first result it finds, with the spurious
Leaf
constructor removed:Trying it out in GHCi:
For contrast, here's a naive depth-first search:
...which of course fails to terminate when searching with
(== 24)
, because the left-most branches are an endless series of 2s.