如何在lisp中检查列表是否为回文?

时间:2015-08-04 17:40:12

标签: lisp common-lisp palindrome

我想通过比较第一个元素和最后一个元素来测试这个列表是否是回文,第二个元素与最后一个元素之前进行比较等等

(setq l '(1 5 7 8 8 7 5 1))
(defun f (l)
  (cond ((null l) 0)
        ((atom l) l)
        (if       (equal (car l) (car(cdr l))))

5 个答案:

答案 0 :(得分:5)

这种比较方法有没有理由?如果没有,使用reverse函数会更容易:

(defun palindrome-p (l)
  (equal l (reverse l)))

答案 1 :(得分:2)

@Pascal解决方案反转整个列表以检查它是否是回文,但这不是必需的。为什么不反转一半呢?

(defun palindrome-p (l)
  (let* ((half (floor (length l) 2))
         (secondhalf (reverse (nthcdr half l))))
    (loop for x in l
          for y in secondhalf
          always (eq x y))))

这个解决方案(我不得不承认,它更“普通lispy”而不是“lispy”)只能分配一半内存的解决方案来反转整个列表,并且在CCL中,在我的笔记本电脑上,列表使用的时间少于一半。

答案 2 :(得分:1)

另一个只包含一半列表的选项:

(defun palindrome-p (list)
  (let* ((length (length list))
         ;; The following lists will NOT include the middle element if length is odd
         (half-length (ceiling length 2))
         (tail (nthcdr half-length list))
         (reversed-head (nreverse (butlast list half-length))))
    (equal tail reversed-head)))

关于这个选项的问题是你得到两个相似长度的列表,你不必担心迭代是否停在最小的那个,并且它更容易适应和稍后调试其他目的。

通常忽略的另一个选项是将整个列表复制到一个向量中。大多数实现采用1或2个架构字(32位/ 64位)来表示cons,因此列表的最坏情况是:

  • 2 × length

这些相同的实现对于向量的头部大约需要1到2个字,每个元素加上1个字,因此向量的最坏情况是:

  • 2 + length

我的意思是,与将整个列表复制到矢量中相比,您将占用列表一半的内存分配成本相同。

折衷方案是找出标头何时与收费和(n)逆转列表或访问非小型列表的第n个元素相比不再是开销。

如果找到此阈值,我会按如下方式重新定义,使其接受a sequence

;; Mere example, I did not research this on any implementation
(defconstant +list-to-vector-overhead-threshold+ 8)

(defun palindrome-p (sequence)
  (if (and (consp sequence)
           (not (null (nthcdr +list-to-vector-overhead-threshold+ sequence))
      (palindrome-p (concatenate 'vector sequence)
      (let ((length (length sequence)))
        (dotimes (i (floor length 2))
          (when (not (equal (elt sequence i) (elt sequence (- length i 1))))
            (return nil)))
        t)))

PS:这里有一些实现'通过实验找到的对象大小(意思是,我可能错误地认为这些数字)具有32位实现:

  • Allegro CL

    • 列出:2 × length
    • 向量:2 + length个字,2个字对齐(即32位,8个字节对齐)
  • Clozure CL

    • 列出:2 × length
    • 向量:1 + length个字,2个字对齐(即32位,8个字节对齐)
  • LispWorks

    • 列出:3 × length
    • 矢量:2 + length
  • SBCL

    • 列出:2 × length
    • 矢量:2 + length

答案 3 :(得分:0)

; Get the reverse of a list
(defun revList (l)
(cond 
    ((null (cdr l)) l)
    (t (append (revList (cdr l)) (list(car l) ) ))
)
)
; Check whether a given a list is a palindrome
(defun palindrome (l)
(cond   ((null l) t)
    ((equal (car l) (car (last l)))(palindrome (cdr (revList (cdr l)))))
)
)

这实现了一个递归函数,如果一个字符串(表示为一个原子的平面列表)是一个回文并且(否则为零),则返回(t)。你可以使用内置的“反向”lisp函数而不是“revList”。

答案 4 :(得分:-1)

(defun palind (l1)
  (if (equal l1 (reverse l1))
      'palindrome
      'no-palindrome))