我正试图解决Problem 14 in Project Euler(找到1到1000000之间最长的Collatz序列)。
我的代码由递归的、记忆化的函数来计算Collatz序列的长度,然后用循环来寻找最大值。请参见下面的代码:
(defparameter *collatz* (make-hash-table))
(setf (gethash 1 *collatz*) 0)
(defun n-collatz (n)
(if (gethash n *collatz*)
(gethash n *collatz*)
(setf (gethash n *collatz*)
(if (evenp n)
(1+ (n-collatz (/ n 2)))
(1+ (n-collatz (1+ (* n 3))))))))
(loop for i from 1 to 1000000 maximize (n-collatz i))
这在Clozure中运行良好,但在Lispworks中导致堆溢出当它婉转地退出时,我找不到发生了什么事。实际上,我不明白为什么这会占用这么多堆空间最大的递归序列是300个something调用我错过了代码中的一些低效吗?
欢迎任何意见对该准则的进一步评论也值得赞赏。
PS:我使用的是LispWorksPersonal版本,它对堆大小进行了限制。
更新
我确实试着按照Rainer Joswig的建议编译,但是没有用。
关于coredump和sds的评论,
or
在本例中确实比if
好,但是我不能用散列表代替向量,因为collatz序列在大约50%的时间内会上升在运行代码之后,哈希表有大约250万个条目。最后,奇怪的是,在测试longish循环(一百万次迭代)的语法时,我成功地重现了这个bug,这个循环只是篡改了一些变量,根本没有收集任何东西我把代码弄丢了,可惜LispWorks只是一败涂地,唉。我最好的猜测是LispWorks的内脏有漏洞或其他内存管理问题。
最佳答案
我在这里看到了两种效率低下的情况:
您正在使用由连续整数序列索引的哈希表您可能应该改用(可扩展的)向量。
你的递归不是尾部递归;你可能更喜欢优化它。
诚然,这些都不能解释堆耗尽的原因。
关于lisp - 为什么这会炸毁Lispworks中的堆?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33020360/