Haskell 中的级别顺序
我有一棵树的结构,我想按级别打印树。
data Tree a = Nd a [Tree a] deriving Show
type Nd = String
tree = Nd "a" [Nd "b" [Nd "c" [],
Nd "g" [Nd "h" [],
Nd "i" [],
Nd "j" [],
Nd "k" []]],
Nd "d" [Nd "f" []],
Nd "e" [Nd "l" [Nd "n" [Nd "o" []]],
Nd "m" []]]
preorder (Nd x ts) = x : concatMap preorder ts
postorder (Nd x ts) = (concatMap postorder ts) ++ [x]
但如何按级别进行呢? “levels tree”应该打印[“a”,“bde”,“cgflm”,“hijkn”,“o”]。 我认为“迭代”是适合此目的的函数,但我无法想出如何使用它的解决方案。请你帮我一下好吗?
I have a structure for a tree and I want to print the tree by levels.
data Tree a = Nd a [Tree a] deriving Show
type Nd = String
tree = Nd "a" [Nd "b" [Nd "c" [],
Nd "g" [Nd "h" [],
Nd "i" [],
Nd "j" [],
Nd "k" []]],
Nd "d" [Nd "f" []],
Nd "e" [Nd "l" [Nd "n" [Nd "o" []]],
Nd "m" []]]
preorder (Nd x ts) = x : concatMap preorder ts
postorder (Nd x ts) = (concatMap postorder ts) ++ [x]
But how to do it by levels? "levels tree" should print ["a", "bde", "cgflm", "hijkn", "o"].
I think that "iterate" would be suitable function for the purpose, but I cannot come up with a solution how to use it. Would you help me, please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您只需要计算所有子树的级别,然后将它们全部压缩到根之后:
遗憾的是,
zipWith
没有做正确的事情,所以我们可以改为使用:更新:有一些担心(我同意)您最初要求的有点奇怪,因为它不是通用的广度优先树到列表转换器。您可能真正想要的是连接以下结果:
You just need to compute the levels for all of the subtrees and zip them all together after the root:
Sadly,
zipWith
doesn't do the right thing, so we can instead use:Update: there is some concern (which I agree with) that what you originally asked is a little weird as it's not a generic breadth-first tree to list convertor. What you probably really want is to concat the result of:
我猜这是家庭作业。假设是这样,那么这里有一些关于如何思考可能引导您找到答案的问题的想法:
在
preorder
中,首先“报告”当前项目,然后递归所有这些节点的尾部。在postorder
中,这两个步骤是相反的。在这两种情况下,递归都是“本地”的,即它一次只需要处理一个节点。levelorder
是这样吗?或者换个角度问,levelorder递归时,递归的结果是否交互?如果是这样,那么,如果不是单个树
,那么递归的“单位”是什么?了解 levelorder 的递归(或迭代..?)的本质将引导您找到一个非常简单而优雅的解决方案。我的版本只有三行长!
顺便说一句,拥有这些实用函数可以使代码在某些地方更加清晰可能会很好:
或者,如果您熟悉 Haskell 中的记录语法,则可以通过更改原始
Tree 定义为:
完整的解决方案:
关键是要认识到
levelorder
需要在Tree
列表上递归。在每一步中,都会提取每个Tree
中的元素,下一步是连接子树:这会在单个扁平列表中生成元素,非常类似于
preorder
和postorder
都是如此,并且是广度优先遍历的通常定义。相反,如果您确实希望按级别对元素进行分组,只需将
++
运算符更改为:
将产生该版本:注意:我已经为所有顶级元素提供了类型签名级函数。这是一个非常值得养成的好习惯,并且会节省您大量的调试时间。
I'm guessing this is homework. On the assumption that it is, then here's some ideas for how to think about the problem that might lead you to an answer:
In
preorder
, first the current item is "reported", then recurse for all this node's tails. Inpostorder
these two steps are done in reverse. In both cases, the recursion is "local", in the sense that it only need deal with one node at a time. Is this true forlevelorder
? Or to ask it another way, whenlevelorder
recurses, do the results of the recursions interact or no? If so, then, what is the "unit" of recursion, if not a singleTree
?Understanding the nature of the recursion (or iteration..?) of
levelorder
will lead you to a solution that very simple and elegant. My version is only three lines long!By the way, it might be nice to have these utility functions to make the code even clearer in some places:
Or, if you are familiar with record syntax in Haskell, you can achieve exactly this by changing your original
Tree
definition to:A full solution:
The key is realizing that
levelorder
requires recursion on a list ofTree
. At each step the elements from eachTree
is extracted, and the next step is upon the concatenation of the subtrees:This produces the elements in a single, flattened list, much like
preorder
andpostorder
do, and is the usual definition of a breadth-first traversal.If instead you really want the elements grouped by level, a single change of the
++
operator to:
will yield that version:Note: I have given type signatures for all top-level functions. This is a really good habit to get into, and will save you considerable time debugging.
这是另一个版本,可以应用于
Tree a
而不是Tree [a]
。如果你想在末尾连接字符串,你可以使用:
Here is another version which can be applied to
Tree a
instead ofTree [a]
.If you want to concatenate the strings at the end you may use:
结果我的做法比我想要的更加笨拙。如果我错了,请纠正我,因为字符串是字符列表,但是您使用的是多态类型,那么像问题中指定的那样打印结果真的那么简单吗?此代码生成字符串列表的列表。 ***克里斯在他更优雅的回答中提醒我有关 concat 的使用!
My approach turned out being a bit more ham-handed than I wanted. Correct me if I'm wrong, though, since strings are lists of characters, but you're using polymorphic types, is it really so straightforward to to print your results out like specified in the problem? This code produces lists of lists of strings. ***Props to Chris in his more elegant answer for reminding me about the use of concat!!
您可以对空列表重复 [] ,这样就不会出现 zipWith 的问题
You can repeat [] for empty list so that you don't get the problem with zipWith