我正在尝试解决Project Euler 中的问题 14(找到 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 次左右的调用。我是否错过了代码中的一些低效率?
任何输入表示赞赏。对代码的进一步评论也受到赞赏。
PS:我使用的是 Lispworks 个人版,它对堆大小施加了限制。
更新 我确实尝试按照 Rainer Joswig 的建议进行编译,但没有帮助。
关于 coredump 和 sds 的评论,or
确实比if
这种情况下要好,但我不能用哈希表代替向量,因为 collatz 序列大约有 50% 的时间上升。运行代码后,哈希表有大约 250 万个条目。
最后,奇怪的是,我在测试一个较长的循环(一百万次迭代)的语法时设法重现了这个错误,该循环只是处理一些变量并且根本没有收集任何东西。不幸的是,我丢失了代码——LispWorks 只是失败了,唉。我最好的猜测是 LispWorks 的内脏中存在一些泄漏或其他内存管理故障。