Lisp中的十进制到二进制 - 创建一个非嵌套列表

时间:2014-03-26 17:07:01

标签: list recursion binary lisp

当到达我的递归情况时,我使用list将未来结果附加到当前的结果,但由于递归,我最终得到了一个嵌套列表。当我有一个导致递归超过五次的数字时,这会导致错误。

任何想法如何在单个普通的非嵌套列表中获得结果,例如:

  

CL-USER 100:8> (BINARY_LIST 4)

     

(1 0 0)

代码&示例输出:

CL-USER 99 : 8 > (defun binary_list (i)
(COND 
    ((= i 0) 0)
    ((= i 1) 1)
    ((= (mod i 2) 0) (list (binary_list (truncate i 2)) 0))
    (t (list (binary_list (truncate i 2)) 1))
    )
)
BINARY_LIST

CL-USER 100 : 8 > (BINARY_LIST 4)
((1 0) 0)

CL-USER 101 : 8 > (BINARY_LIST 104)
((((# 1) 0) 0) 0)

2 个答案:

答案 0 :(得分:8)

你快到了。您需要做的就是将list替换为nconc

(defun binary-list (n)
  (cond ((= n 0) (list 0))
        ((= n 1) (list 1))
        (t (nconc (binary-list (truncate n 2)) (list (mod n 2))))))

您可以通过收集整数除法中的两个值来避免同时调用truncatemod

(defun binary-list (n)
  (assert (>= n 0))
  (multiple-value-bind (q r) (floor n 2)
    (if (zerop q)
        (list r)
        (nconc (binary-list q) (list r)))))

请注意,此算法是二次,因为nconc必须在每次迭代时遍历结果。通过传递累加器可以避免这种情况:

(defun binary-list (n &optional acc)
  (assert (>= n 0))
  (multiple-value-bind (q r) (floor n 2)
    (if (zerop q)
        (cons r acc)
        (binary-list q (cons r acc)))))

现在我们有一个尾递归函数,可以通过现代编译器编译为迭代。

您可以使用的另一个优化技巧(事实上,应该由编译器完成 - 尝试disassemble来检查!)正在使用ash和{{ 3}}而不是更通用和昂贵的logand

(defun binary-list (n &optional acc)
  (cond ((zerop n) (or acc (list 0)))
        ((plusp n)
         (binary-list (ash n -1) (cons (logand 1 n) acc)))
        (t (error "~S: non-negative argument required, got ~s" 'binary-list n))))

顺便提一句,lispers通常在符号中使用短划线而不是下划线,因此如果您不想冒犯我们温柔的美学,则binary_list应为binary-list

答案 1 :(得分:1)

在我看来,这是每次都能达到预期效果的最直接,最简单的方式:

(defun mvp-binary-from-decimal (n r)
    (if (zerop n)
    r
    (multiple-value-bind (a b)
        (floor n 2)
        (mvp-binary-from-decimal a (cons b r)))))

(defun binary-from-decimal (n)
    (if (and (numberp n) (plusp n))
    (mvp-binary-from-decimal n '())
    (if (eql n 0) '(0) nil)))

在粘液,sbcl,clisp中测试 - 使用如下:

CL-USER> (binary-from-decimal 100)
(1 1 0 0 1 0 0)
CL-USER> (binary-from-decimal 10)
(1 0 1 0)
CL-USER> (binary-from-decimal 0)
(0)

为什么这可能是实现此类功能的最理想方式,有一些高级原因,但就目前而言,足以说它干净,礼貌,可读并且始终有效。