【问题标题】:A function to compare sets; help improving efficiency比较集合的功能;帮助提高效率
【发布时间】:2011-06-23 06:18:42
【问题描述】:

我正在尝试编写一个函数来比较两个列表以查看它们是否代表相同的集合。那就是'(a b c d d)'(d c b a d) 代表同一个集合。元素可以按任意顺序排列。

这就是我所拥有的,它有效:

(defun samesetp (list1 list2)
  (cond
    ((null list1) (null list2))
    ((eq list2 (remove (car list1) list2 :count 1)) nil)
    (t (samesetP (cdr list1) (remove (car list1) list2 :count 1))))))

我不喜欢这样的原因是 (remove (car list1) list2 :count 1)) 被计算了两次 - 一次是为了测试 remove 操作是否真的删除了任何东西,一次是为了递归地测试没有该元素的列表的其余部分。

谁能提出一种在不使用不同算法的情况下改进这一点的方法?

【问题讨论】:

  • 你应该使用哈希表,这会将复杂度从 O(n^2) 降低到 O(n)。
  • 我很困惑。您正在使用一种糟糕的算法,并且希望改进,只要它们不涉及修复错误的算法。为什么?正如@leppie 所说,使用哈希表。或者对两个列表进行排序,然后并行遍历它们。与您关注的微优化相比,更好的算法会产生更大的影响。
  • 冷静下来,我们不允许使用哈希表。这是家庭作业问题的一部分。如果你能想到一个更高效的算法,可以包含在大约 10 行代码之内,请赐教。
  • 不要在自己的行上使用尾括号。 Lisp 不是 C 或 Java。
  • 支持 Rainer 的评论 - 见 mumble.net/~campbell/scheme/style.txt

标签: lisp common-lisp


【解决方案1】:

我猜你不允许使用内置函数来解决问题,但请注意有一个:

(set-difference list1 list2)

【讨论】:

  • ITYM set-exclusive-or。对于set-difference,参数的顺序很重要。
【解决方案2】:
(defun samesetp (list1 list2)
    (cond
        ((null list1) (null list2))
        ((eq list2 (remove (car list1) list2 :count 1)) nil)
        (t (samesetP (cdr list1) (remove (car list1) list2 :count 1))))
    )
)

首先让我们正确格式化它:

(defun samesetp (list1 list2)
  (cond ((null list1) (null list2))
        ((eq list2 (remove (car list1) list2 :count 1)) nil)
        (t (samesetP (cdr list1) (remove (car list1) list2 :count 1)))))

如果您使用表单两次并且想要更改它,那么您需要存储一个值。 LET 就是它的构造。如果它不适合一个 COND,那么您需要第二个。

(defun samesetp (list1 list2)
  (cond ((null list1) (null list2))
        (t (let ((list3 (remove (car list1) list2 :count 1)))
             (cond ((eq list2 list3) nil)
                   (t (samesetP (cdr list1) list3)))))))

现在,EQ 不能用于比较列表。使用 EQUAL。

(defun samesetp (list1 list2)
  (cond ((null list1) (null list2))
        (t (let ((list3 (remove (car list1) list2 :count 1)))
             (cond ((equal list2 list3) nil)
                   (t (samesetP (cdr list1) list3)))))))

这里的 COND 是多余的,使用 IF:

(defun samesetp (list1 list2)
  (if (null list1)
      (null list2)
    (let ((list3 (remove (car list1) list2 :count 1)))
      (if (equal list2 list3)
          nil
        (samesetP (cdr list1) list3)))))

现在,您只需让函数执行作业中要求的操作。但无论如何,这是你的功课。

【讨论】:

  • 谢谢。我看到 LET 在这里可能真正有帮助。
  • 如果这对您有帮助,您应该将 Rainer 的回答标记为已接受。我会补充说这是一个很好的答案,所以+1。
  • 是的,我确实标记了它。谢谢 Rainer,非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 2020-01-30
  • 2019-03-10
相关资源
最近更新 更多