Functional programming 纯函数自底向上树算法
假设我想写一个算法,处理一个不可变的树数据结构,它有一个叶子列表作为输入。它需要返回一棵新树,并从这些叶子向上改变老树 我的问题是,如果叶子在列表中,如果不重建整个树检查,似乎没有办法实现这一纯功能性操作,因为您总是需要返回一个完整的新树作为操作的结果,并且您不能改变现有的树 这是函数式编程中的一个基本问题,只有使用更合适的算法才能避免,还是我遗漏了什么Functional programming 纯函数自底向上树算法,functional-programming,tree,immutability,Functional Programming,Tree,Immutability,假设我想写一个算法,处理一个不可变的树数据结构,它有一个叶子列表作为输入。它需要返回一棵新树,并从这些叶子向上改变老树 我的问题是,如果叶子在列表中,如果不重建整个树检查,似乎没有办法实现这一纯功能性操作,因为您总是需要返回一个完整的新树作为操作的结果,并且您不能改变现有的树 这是函数式编程中的一个基本问题,只有使用更合适的算法才能避免,还是我遗漏了什么 编辑:我不仅希望避免重新创建整个树,而且函数算法的时间复杂度应该与变异变量相同。这取决于函数编程语言。例如,在Haskell(一种函数式编程语
编辑:我不仅希望避免重新创建整个树,而且函数算法的时间复杂度应该与变异变量相同。这取决于函数编程语言。例如,在Haskell(一种函数式编程语言)中,结果是在最后一刻计算出来的;当他们真正需要的时候 在您的示例中,假设因为您的函数创建了一个新的树,所以必须处理整个树,而实际上函数只是传递给下一个函数,并且只在必要时执行 惰性计算的一个很好的例子是Haskell中的,它通过消除数字列表中当前数字的倍数来创建素数。请注意,数字列表是无限的。取自
素数::[Integer]
素数=筛[2..]
哪里
筛子(p:xs)=p:sieve[x | x 0]
你可能喜欢阅读
到目前为止,我所看到的最有希望的(当然不是很长…)是:它基本上保留了一个单独的结构,从节点到根的反向路径,并对这个单独的结构进行局部编辑 它可以一次完成多个局部编辑,其中大部分是固定时间的,然后将它们写回树(重建到根的路径,这是唯一需要更改的节点) 拉链是一个链接(请参见标题Zippers-功能树编辑) 在OCaml中有一个实现 免责声明:我已经编程很长时间了,但几周前才开始函数式编程,直到上周才听说过树的函数式编辑问题,所以可能还有其他我不知道的解决方案
尽管如此,看起来拉链还是能满足大多数人的愿望。如果在O(logn)或以下还有其他选择,我希望听到它们。我最近写了一个算法,它完全符合您所描述的- 它分两个阶段工作:
- 没有节点突变,结果是一棵不可变的树
- 复杂度为O(n)
- 忽略传入列表中的循环引用
primes :: [Integer]
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]