快速排序(Lisp版本)

快速排序是一种常见的排序手段,由C.A.R.Hoare在1960年提出。其基本思路为:

  1. 设定一个分界值,通常为第一个元素;

  2. 遍历列表,将所有小于分界值的元素集中到列表的左侧,所有大于或等于分界值的元素集中到右侧;

  3. 分别对左侧和右侧的元素进行快排;

  4. 重复上述的步骤,排序完成;

在平均状况下,排序n个元素需要$O(nlog n)$复杂度,最坏情况下需要$O(n^2)$,但一般很少出现这种情况。

从算法的原理可以看出,需要多次执行重复的操作,自然采用递归可以减少很多代码,若问递归技术哪家强?首屈一指Lisp,下面给出CL版本的快排实现(简易版本,只支持数字类型的列表,其他类型的排序只需增加一个比较函数即可,本文不扩展):

(defun quickSort (lst)
    (let
        (
            (len (list-length lst))
            (st (lambda (l pk)   ;; st函数实现上述第2步
                    (let ((left nil) (right nil))
                        (dolist (each l) (if (< each pk) (push each left) (push each right)))
                        (values left right)
                    )
                )
            )
        )
        (if
            (< len 2)
            lst
            (multiple-value-bind (l r) (st (cdr lst) (car lst)) (append (quickSort l) (cons (car lst) (quickSort r))))
        )
    )
)


(quickSort '(1 2 6 3 5 4))  => (1 2 3 4 5 6)

st函数可以用宏来实现:

(defmacro st (lst pk)
    (let ((gslist (gensym)))
        `(let ((,gslist ,lst))
            (let ((left nil) (right nil))
                (dolist (each ,gslist) (if (< each ,pk) (push each left) (push each right)))
                (values left right)
            )
        )
    )
)
(defun quickSort (lst)
    (let
        (
            (len (list-length lst))
        )
        (if
            (< len 2)
            lst
            (multiple-value-bind (l r) (st (cdr lst) (car lst)) (append (quickSort l) (cons (car lst) (quickSort r))))
        )
    )
)