如何递归检查列表是否在Lisp中排序?

时间:2015-10-09 01:23:35

标签: list recursion lisp common-lisp

我想编写一个检查列表的递归函数,如果列表按升序排列则返回true,否则返回NIL。如果列表为空,则仍然如此。我是Lisp的新手,所以它仍然非常令人困惑。

(defun sorted (x)
  (if (null x)
      T
      (if (<= car x (car (cdr x)))
          (sorted (cdr x))
          nil)))

3 个答案:

答案 0 :(得分:1)

递归版:

(defun sorted (list)
  (or (endp list)
      (endp (cdr list))
      (and (<= (first list) (second list))
           (sorted (cdr list)))))

更加惯用的基于循环的谓词接受:test参数:

(defun sortedp (list &key (test #'<=))
  (loop for (a b) on list
        while b
        always (funcall test a b)))

接受:key的版本;我们只对每个访问过的元素调用key函数:

(defun sortedp (list &key (test #'<=) (key #'identity))
  (loop for x in list
        for old = nil then new
        for new = (funcall key x)
        for holdp = T then (funcall test old new)
        always holdp))

一些测试:

(loop for k in '(() 
                ((1)) 
                ((1) (2)) 
                ((2) (1)) 
                ((1) (2) (3)) 
                ((3) (2) (1)))
      collect (sortedp k :test #'> :key #'car))

=> (T T NIL T NIL T)

这个也适用于其他类型的序列:

(defun sortedp (sequence &key (test #'<=) (key #'identity))
  (reduce (lambda (old x &aux (new (funcall key x)))
            (if (or (eq old t)
                    (funcall test old new))
                new
                (return-from sortedp nil)))
          sequence
          :initial-value t))

上述测试给出:

(T 1 NIL 1 NIL 1)

...由于广义布尔值,这是正确的结果。

答案 1 :(得分:1)

如果你正在做作业(似乎是这样),那么上面的答案都没问题。如果您只是学习Lisp,并且没有关于递归的约束,那么下面的内容可能会让您对Lisp的强大功能有所了解:

(defun sorted (l) 
  (or (null l) (apply #'< l)))

答案 2 :(得分:0)

您的解决方案的第一个问题是基本情况您需要停止在列表的末尾,但是当查看最后一个元素时,您需要元素来进行比较。调用(car x)

时,parens也丢失了
(defun sorted (list)
  (if (endp (cddr list))
      (<= (car list) (cadr list))
      (and (<= (car list) (cadr list))
           (sorted (cdr list)))))

请记住,在CL

中不鼓励使用递归解决方案