Scheme 语言实现快速排序算法

使用 Scheme 语言实现快速排序是一个很好的练习,因为它可以展示 Scheme 在处理列表和使用高阶函数方面的优雅之处。下面是一个用 Scheme 实现快速排序的程序,我将分步解释其原理。

1. 快速排序的基本思想

快速排序(Quicksort)是一种高效的排序算法,其核心思想是分治法(Divide and Conquer)

  1. 选择基准(Pivot):从待排序的列表中选择一个元素作为基准。在我们的实现中,为了简单起见,我们选择列表的第一个元素。
  2. 分区(Partition):将列表分为两个子列表。一个子列表包含所有小于基准的元素,另一个子列表包含所有大于或等于基准的元素。
  3. 递归排序:对这两个子列表分别递归地进行快速排序。
  4. 合并:将排好序的“小于”子列表、基准元素和排好序的“大于或等于”子列表连接起来,形成最终的有序列表。

当递归到只剩一个元素或空列表时,递归终止。

2. Scheme 快速排序程序

以下是用 Scheme 语言编写的快速排序函数 quicksort

(define (quicksort lst)
  (if (null? lst)
      '() ; 如果列表为空,返回空列表
      (let* ((pivot (car lst)) ; 选择列表的第一个元素作为基准
             (rest (cdr lst)) ; 剩余的列表
             (less (filter (lambda (x) (< x pivot)) rest)) ; 筛选出小于基准的元素
             (greater-equal (filter (lambda (x) (>= x pivot)) rest))) ; 筛选出大于或等于基准的元素
        (append (quicksort less) ; 递归排序小于基准的子列表
                (list pivot) ; 将基准元素转换为列表形式
                (quicksort greater-equal))))) ; 递归排序大于或等于基准的子列表

3. 程序解读

  • (define (quicksort lst) ...):定义一个名为 quicksort 的函数,它接受一个列表 lst 作为参数。

  • (if (null? lst) '()):这是递归的终止条件。如果传入的列表是空的(null? 检查),那么它已经是排好序的,直接返回一个空列表 '()

  • (let* ((pivot (car lst)) ...)):使用 let* 绑定局部变量,这比 let 更方便,因为它允许后面的绑定依赖于前面的绑定。

    • (pivot (car lst))car 函数返回列表的第一个元素,我们将其作为基准 pivot
    • (rest (cdr lst))cdr 函数返回列表的其余部分,我们将其赋值给 rest
  • (filter (lambda (x) (< x pivot)) rest):这里是 Scheme 强大之处的体现。我们使用 高阶函数 filter

    • filter 函数接受两个参数:一个谓词(一个返回 #t#f 的函数)和一个列表。它会返回一个新列表,其中只包含那些满足谓词条件的元素。
    • **(lambda (x) (< x pivot))** 是一个匿名函数(lambda 表达式),它检查一个元素 x 是否小于 pivot
    • 这行代码的效果就是从 rest 列表中筛选出所有小于 pivot 的元素,并赋值给 less
  • (filter (lambda (x) (>= x pivot)) rest):与上面类似,这行代码筛选出所有大于或等于 pivot 的元素,并赋值给 greater-equal

  • (append (quicksort less) (list pivot) (quicksort greater-equal)):这是将排序结果组合起来的关键一步。

    • 我们递归地调用 quicksort 来排序 lessgreater-equal 两个子列表。
    • (list pivot) 将基准元素 pivot 包装成一个单元素的列表。
    • 最后,append 函数将三个列表连接起来,得到最终的有序列表。

4. 示例

假设我们有一个列表 (6 5 2 7 3 1 4),调用 (quicksort '(6 5 2 7 3 1 4)),程序的执行过程如下:

  1. 基准6
  2. 小于 6 的子列表是 (5 2 3 1 4)
  3. 大于或等于 6 的子列表是 (7)
  4. (5 2 3 1 4)(7) 递归调用 quicksort
  5. 最终,append 会将 (quicksort '(5 2 3 1 4)), (6)(quicksort '(7)) 拼接起来,得到结果 (1 2 3 4 5 6 7)

5. 运行结果

您可以在任何 Scheme 解释器(如 Racket 或 Chez Scheme)中运行这段代码:

(quicksort '(6 5 2 7 3 1 4))
; => (1 2 3 4 5 6 7)

(quicksort '(10 5 8 2 1))
; => (1 2 5 8 10)

(quicksort '())
; => ()

(quicksort '(1))
; => (1)

这个实现简洁、优雅,充分利用了 Scheme 的列表操作和高阶函数特性,是函数式编程思维的一个经典范例。

posted @ 2025-08-27 19:54  立体风  阅读(9)  评论(0)    收藏  举报