• 不一样的快速排序


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

    在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 ,这里用了列表推导式。(同样注意,等于的情况要并在小于或者大于之中)

    最后将三部分拼接起来。

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

  • 相关阅读:
    谈谈图片上传及canvas压缩的流程
    前端应该懂得初级Web分析指标
    java OPENCV 连通域, Imgproc.findContours 例子,参数说明
    [学习opencv]高斯、中值、均值、双边滤波
    Opencv 图像叠加 添加水印
    帧间提取水印
    opencv mat 转灰度图
    编写一条sql命令,sql删除没有中文的表
    使用JavaCV/OpenCV抓取并存储摄像头图像
    周掌柜
  • 原文地址:https://www.cnblogs.com/gaoduan/p/4162294.html
Copyright © 2020-2023  润新知