Common Lisp中的线性递归列表差异函数

时间:2009-03-04 13:59:50

标签: algorithm recursion lisp common-lisp

我正在通过this教程获得乐趣,并且最后一件事就是他坚持说:“练习:给出联合和差异的线性递归实现。” (列表)

联盟,没有汗水。

差异,汗水。

尝试看起来像这样。 。

(defun list-diff (L1 L2)
  (cond
    ((null L1) L2) 
    ((null (member (first L1) L2)) (cons (first L1) (list-diff (rest L1) L2)))
    (t (list-diff (rest L1) L2))
  )
)

现在,它返回L1中不在L2中的所有元素,但它只返回所有L2(显然)。类似地,如果我将第3行中的L2更改为“nil”,那么它只返回不在L2中但不包含L2的所有L1。

我在解决方法上的尝试看起来并不是递归的,当它们出现时,我最终会得到堆栈溢出(就像我尝试在某处调用(list-diff L2 L1))。

他的任何其他练习,例如list-intersection,只需要遍历L1的元素。在这里,我想从L2中运行关键元素,或者运行(list-diff L2 L1),然后将两者的结果联合起来,但这不再是线性递归。

思考?

(不是功课,真的。我以为我会试着看一些LISP的乐趣。)

编辑:基于响应正确执行此操作的函数是:

(defun list-diff (L1 L2)
  (cond
    ((null L1) nil)
    ((null (member (first L1) L2)) (cons (first L1) (list-diff (rest L1) L2)))
    (t (list-diff (rest L1) L2))
  )
)

2 个答案:

答案 0 :(得分:6)

set difference操作L1 \ L2被定义为所有元素e,使得e在L1中但e不在L2中。所以在我看来,你的第二次尝试实际上是正确的:

  

同样,如果我改变了L2   3到“nil”,然后它只返回所有   L1不在L2中,但没有   L2。

看起来你正在尝试计算symmetric difference,虽然我不清楚这是练习要求的内容。

如果你想要聪明一点,你可以将第三个列表传递给函数作为累加器。当L1有元素时,在(null (member (first L1) L2))时将第一个元素推入累加器(并递归调用)。当L1为null时,检查L2的元素与累加器列表,执行相同的操作。当L1和L2为空时,返回累加器列表。

答案 1 :(得分:4)

在Lisp中,这是'set difference'的定义:

set-difference list1 list2 &key (test #'eql) test-not (key #'identity)
   Function
   Returns a list of elements of list1 that do not appear in list2. 

这是你修改过的实现:

(defun list-diff (L1 L2)
  (cond
    ((null L1) L1)
    ((member (first L1) L2) (list-diff (rest L1) L2))
    (t (cons (first l1) (list-diff (rest l1) l2)))))