不一样的快速排序

快速排序是一个从程序设计基础开始,到数据结构,到算法都会提到的经典例子,常见的做法是取开头元素作为主元,将不大于它的元素放在前面,比它大的放在后面,而前面和后面再次递归调用。

在scheme当中是这个样子的:

 1 #lang racket
 2 (define (smaller x l) 
 3     (cond 
 4         [(null? l) null]
 5            
 6         [(>= x (car l)) (cons (car l) (smaller x (cdr l)))]
 7         [else (smaller x (cdr l))]))
 8 
 9 (define (bigger x l) 
10     (cond   [(null? l)         '()]
11             [(< x (car l)) (cons (car l) (bigger x (cdr l)))]
12             [else             (bigger x (cdr l))]  ))
13 
14 
15 (define (quicksort l)  
16     
17        (cond   [(null? l) '()]
18                [(not (pair? l)) l]
19                [else 
20                 (let (
21                        [small (quicksort (smaller (car l) (cdr l)))]
22                        [big   (quicksort (bigger  (car l) (cdr l)))]
23                      )
24                (append small (cons (car l) big)) )]
25         ))
26 
27 (define l (list 8 3 2 1 5 4 6 9 9 7))
28 (display ( quicksort l))

简单的解释一下,先写了两个辅助性的函数:smaller  bigger,接受参数为一个参考主元值和一个列表,返回的是那个列表中比参考值小的所有元素的值构成的列表,实际上是一个filter,完全可以用filter来直接做。 注意的一点是,bigger 和 smaller当中的某一个需要包含相等的情况。

quicksort 函数体很简单,如果列表是空的,返回空列表;

如果参数并不是一个列表,而只是一个数,返回这个数;

如果是一个列表,递归定义small 和 big ,然后 执行append small (cons (car l) big) ,也就是先构造  cons (car l) big,将当前主元值和big连接起来,在把它整体接在small的后面。

程序看起来是不是比之前用C++ 写的话简洁很多~

使用filter 的scheme版本:

 1 #lang racket
 2 (define (quicksort l)  
 3        (cond   [(null? l) '()]
 4                [(not (pair? l)) l]
 5                [else 
 6                 (let ( [small (quicksort (filter (lambda (y) (>= (car l) y)) (cdr l) ))]
 7                        [big   (quicksort (filter  (lambda (y) (< (car l) y)) (cdr l) ))])
 8                (append small (cons (car l) big)) )]))
 9 
10 (define l (list 8 3 2 1 5 4 6 9 9 7))
11 (display ( quicksort l))

比之前看起来简单很多了吧~

如果用haskell 来写的话:

1 myquicksort :: (Ord a) => [a] -> [a]
2 myquicksort [] = []
3 myquicksort (x:xs) = 
4     let small = myquicksort [a | a <-xs,a <= x]
5         large = myquicksort [a | a <-xs,a > x ]
6     in small ++ [x] ++ large

哇,看起来不错~

简单解释一下,第一行是一个类型声明,可以作为排序函数的参数的元素必须是可以比较的,也就是属于Ord类型的

后面是一个简单的分类:

1. 参数是[] ,返回[]

2. 参数是list,用模式匹配分解 x:xs,同样利用filter来实现small 和 large ,这里用了列表推导式。(同样注意,等于的情况要并在小于或者大于之中)

最后将三部分拼接起来。

函数式编程还是比较有魅力的,但其实不只是上面展示的这种简洁,更舒服的是自定义很多语法糖,并且元语法很少,可以快速有效的掌握,而更多的语法糖不仅可以学会使用,还可以知道是如何构造出来的!

原文地址:https://www.cnblogs.com/gaoduan/p/4162294.html