Haskell 中的级别顺序

发布于 2024-08-30 15:00:11 字数 650 浏览 3 评论 0原文

我有一棵树的结构,我想按级别打印树。

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

雪化雨蝶 2024-09-06 15:00:11

您只需要计算所有子树的级别,然后将它们全部压缩到根之后:

levels :: Tree [a] -> [[a]]
levels (Nd a bs) = a : foldr (zipWith' (++)) [] (map levels bs)

遗憾的是, zipWith 没有做正确的事情,所以我们可以改为使用:

zipWith' f xs [] = xs
zipWith' f [] xs = xs
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

更新:有一些担心(我同意)您最初要求的有点奇怪,因为它不是通用的广度优先树到列表转换器。您可能真正想要的是连接以下结果:

levels' (Nd a bs) = [a] : foldr (zipWith' (++)) [] (map levels' bs)

You just need to compute the levels for all of the subtrees and zip them all together after the root:

levels :: Tree [a] -> [[a]]
levels (Nd a bs) = a : foldr (zipWith' (++)) [] (map levels bs)

Sadly, zipWith doesn't do the right thing, so we can instead use:

zipWith' f xs [] = xs
zipWith' f [] xs = xs
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

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:

levels' (Nd a bs) = [a] : foldr (zipWith' (++)) [] (map levels' bs)
百变从容 2024-09-06 15:00:11

我猜这是家庭作业。假设是这样,那么这里有一些关于如何思考可能引导您找到答案的问题的想法:

preorder 中,首先“报告”当前项目,然后递归所有这些节点的尾部。在postorder中,这两个步骤是相反的。在这两种情况下,递归都是“本地”的,即它一次只需要处理一个节点。 levelorder 是这样吗?或者换个角度问,levelorder递归时,递归的结果是否交互?如果是这样,那么,如果不是单个,那么递归的“单位”是什么?

了解 levelorder 的递归(或迭代..?)的本质将引导您找到一个非常简单而优雅的解决方案。我的版本只有三行长!

顺便说一句,拥有这些实用函数可以使代码在某些地方更加清晰可能会很好:

element :: Tree a -> a
element (Nd x _) = x
subtrees :: Tree a -> [Tree a]
subtrees (Nd _ s) = s

或者,如果您熟悉 Haskell 中的记录语法,则可以通过更改原始 Tree 定义为:

data Tree a = Nd { element :: a, subtrees :: [Tree a] }
    deriving Show

完整的解决方案:

关键是要认识到 levelorder 需要在 Tree 列表上递归。在每一步中,都会提取每个Tree 中的元素,下一步是连接子树:

levelorder :: Tree a -> [a]
levelorder t = step [t]
    where step [] = []
          step ts = map element ts ++ step (concatMap subtrees ts)

这会在单个扁平列表中生成元素,非常类似于 preorderpostorder 都是如此,并且是广度优先遍历的通常定义。

相反,如果您确实希望按级别对元素进行分组,只需将 ++ 运算符更改为 : 将产生该版本:

bylevel :: Tree a -> [[a]]
bylevel t = step [t]
    where step [] = []
          step ts = map element ts : step (concatMap subtrees ts)

注意:我已经为所有顶级元素提供了类型签名级函数。这是一个非常值得养成的好习惯,并且会节省您大量的调试时间。

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. In postorder 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 for levelorder? Or to ask it another way, when levelorder recurses, do the results of the recursions interact or no? If so, then, what is the "unit" of recursion, if not a single Tree?

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:

element :: Tree a -> a
element (Nd x _) = x
subtrees :: Tree a -> [Tree a]
subtrees (Nd _ s) = s

Or, if you are familiar with record syntax in Haskell, you can achieve exactly this by changing your original Tree definition to:

data Tree a = Nd { element :: a, subtrees :: [Tree a] }
    deriving Show

A full solution:

The key is realizing that levelorder requires recursion on a list of Tree. At each step the elements from each Tree is extracted, and the next step is upon the concatenation of the subtrees:

levelorder :: Tree a -> [a]
levelorder t = step [t]
    where step [] = []
          step ts = map element ts ++ step (concatMap subtrees ts)

This produces the elements in a single, flattened list, much like preorder and postorder 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:

bylevel :: Tree a -> [[a]]
bylevel t = step [t]
    where step [] = []
          step ts = map element ts : step (concatMap subtrees ts)

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.

如若梦似彩虹 2024-09-06 15:00:11

这是另一个版本,可以应用于Tree a而不是Tree [a]

levelorder :: Tree a -> [[a]]
levelorder (Nd x ts) = [x]:(ziplist (map levelorder ts))

ziplist :: [[[a]]] -> [[a]]
ziplist l = if null ls then [] else (concat heads):(ziplist tails)
    where
        ls = filter (not.null) l
        heads = map head ls
        tails = map tail ls

如果你想在末尾连接字符串,你可以使用:

levelorder2 :: Tree [a] -> [[a]]
levelorder2 = (map concat).levelorder

Here is another version which can be applied to Tree a instead of Tree [a].

levelorder :: Tree a -> [[a]]
levelorder (Nd x ts) = [x]:(ziplist (map levelorder ts))

ziplist :: [[[a]]] -> [[a]]
ziplist l = if null ls then [] else (concat heads):(ziplist tails)
    where
        ls = filter (not.null) l
        heads = map head ls
        tails = map tail ls

If you want to concatenate the strings at the end you may use:

levelorder2 :: Tree [a] -> [[a]]
levelorder2 = (map concat).levelorder
醉梦枕江山 2024-09-06 15:00:11
levels :: (Tree a) -> [[a]]
levels (Nd x ts) = [[x]] ++ levelshelper ts

level2 = (map concat).levels

levelshelper :: [Tree a] -> [[a]]
levelshelper [] = []
levelshelper xs = (map (\(Nd x ts) -> x) xs) : (levelshelper (extractl xs))

--get the next level's Nd's 
extractl :: [Tree a] -> [Tree a]
extractl [] = []
extractl ((Nd x ts):xs) = ts ++ (extractl xs)

结果我的做法比我想要的更加笨拙。如果我错了,请纠正我,因为字符串是字符列表,但是您使用的是多态类型,那么像问题中指定的那样打印结果真的那么简单吗?此代码生成字符串列表的列表。 ***克里斯在他更优雅的回答中提醒我有关 concat 的使用!

levels :: (Tree a) -> [[a]]
levels (Nd x ts) = [[x]] ++ levelshelper ts

level2 = (map concat).levels

levelshelper :: [Tree a] -> [[a]]
levelshelper [] = []
levelshelper xs = (map (\(Nd x ts) -> x) xs) : (levelshelper (extractl xs))

--get the next level's Nd's 
extractl :: [Tree a] -> [Tree a]
extractl [] = []
extractl ((Nd x ts):xs) = ts ++ (extractl xs)

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!!

情徒 2024-09-06 15:00:11

您可以对空列表重复 [] ,这样就不会出现 zipWith 的问题

levels :: Tree a -> [[a]]
levels Empty          = repeat []
levels (Branch x l r) = [x] : zipWith (++) (levels l) (levels r)

You can repeat [] for empty list so that you don't get the problem with zipWith

levels :: Tree a -> [[a]]
levels Empty          = repeat []
levels (Branch x l r) = [x] : zipWith (++) (levels l) (levels r)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文