【发布时间】:2014-01-27 00:36:02
【问题描述】:
This submission to Programming Praxis 给出了一个 O(n) 函数,它“撤消”二叉搜索树的前序遍历,将列表转换回树。提供缺失数据声明:
数据树 a = 叶 |分支 {value::a, left::Tree a, right:: Tree a} 推导 (Eq, Show) fromPreOrder :: Ord a => [a] -> 树 a fromPreOrder [] = 叶 fromPreOrder (a:as) = 分支 a l (fromPreOrder bs) 在哪里 (l,bs) = 小于 a as 小于 n [] = (叶,[]) 小于 n 全部@(a:as) | a >= n =(叶子,全部) |否则 = (分支 a l r,cs) 其中 (l,bs) = 小于 a 为 (r,cs) = 小于 n bs很明显,在每个递归步骤中都会向树中添加一个构造函数,这是其效率的关键。
唯一的“问题”是列表是手动通过计算线程化的,这不是一种非常 Haskelian 的方法,并且很难看出它实际上是在单线程中逐个元素地消耗的方式。
我尝试使用状态单子 (prettified on Codepad) 来纠正这个问题:
导入 Control.Monad.State 数据树 a = 叶 |分支 {root::a, left::Tree a, right::Tree a} 推导 (Eq,Show) peek = 状态 peek' 其中 偷看' [] =(什么都没有,[]) peek' a@(x:_) = (只是 x,a) pop = 状态 pop' 其中 pop' [] = error "试图读到列表末尾" pop' (_:xs) = ((),xs) prebuild'::Ord a => State [a] (树 a) 预构建' = 做 下一个 返回叶子 只是 x -> 做 流行音乐 leftpart 返回叶子 只是 x -> 做 如果 x [a] -> 树 a prebuild = evalState prebuild'不幸的是,这看起来非常混乱,而且似乎并不容易推理。
一个想法我还没有得到任何地方(部分原因是我对基本概念的理解不够深入,很可能):我可以在列表上使用左折叠来构建一个continuation 最终生成树?那可能吗?还有,这算不算疯狂?
另一个想法是把它写成一棵展开的树,但我认为不可能有效地做到这一点;列表最终会被遍历太多次,程序将是 O(n^2)。
编辑
从另一个方向来看,我有一种挥之不去的怀疑,即有可能提出一种算法,该算法首先将列表分成递增段和递减段,但我还没有找到具体的事情要做有了这个想法。
【问题讨论】:
标签: haskell tree binary-search-tree tree-traversal