快速排序

快排的详细介绍,简单的说就是取输入序列中的首元素m,然后将除首元素m以外的其它元素分成两组,小于等于m的一组和大于m的一组.将3组元素组合成输入队列:小于等于m + m + 大于m.

下面看一个用haskell实现的快速排序代码:

  1. quicksort :: (Ord a) => [a] -> [a]
  2. quicksort [] = []
  3. quicksort (x:xs) =
  4. let smallerSorted = quicksort [a | a <- xs, a <= x]
  5. biggerSorted = quicksort [a | a <- xs, a > x]
  6. in smallerSorted ++ [x] ++ biggerSorted

haskell中有列表解析(List Comprehension)的支持,所以smallerSortedbiggerSorted两个集合通过列表解析很方便的就生成了.而Scheme中没有列表解析,所以首先要实现一个类似列表解析的功能将附后条件的列表元素筛选出来:

  1. (define my-filter
  2. (lambda (f l)
  3. (define iter
  4. (lambda (l a)
  5. (if (not (pair? l)) a
  6. (let* ([h (car l)] [r (if (f h) (append a (list h)) a)])
  7. (iter (cdr l) r)))))
  8. (iter l '())))

filter的功能是输入一个条件判断函数f和一个列表l,filter将l中所有满足f的元素组成一个列表并返回.上面代码使用的是accumulator模式,也就是在迭代模式,通过传进一个a参数在每次递归调用中保存结果.可以注意到这个filter的定义是满足尾递归的.

下面是filter的递归版本:

  1. (define my-filter
  2. (lambda (f l)
  3. (if (not (pair? l)) '()
  4. (let ([h (car l)])
  5. (if (f h) (cons h (filter f (cdr l)))
  6. (filter f (cdr l)))))))

通过cps变换将上述函数转换成尾递归的:

  1. (define my-filter
  2. (lambda (f l)
  3. (define cps
  4. (lambda (l k)
  5. (if (not (pair? l)) (k '())
  6. (let ([h (car l)])
  7. (if (f h) (cps (cdr l) (lambda (x) (k (cons h x))))
  8. (cps (cdr l) (lambda (x) (k x))))))))
  9. (cps l (lambda (x) x))))

有了filter之后我们就可以实现qsort了:

  1. (define qsort
  2. (lambda (l)
  3. (if (not (pair? l)) '()
  4. (let* ([m (car l)]
  5. [large (my-filter (lambda (x) (if (> x m) #t #f)) (cdr l))]
  6. [less (my-filter (lambda (x) (if (<= x m) #t #f)) (cdr l))])
  7. (append (qsort less) (cons m (qsort large)))))))
  8. >(qsort `(5 1 4 2 3 3 7)) -> (1 2 3 3 4 5 7)

比较下与haskell版的区别,首先是没有列表解析,其次是没有模式匹配,需要用if表达式处理.

当然haskell中也是由filter的,下面就是haskell快排的filter版本:

  1. quicksort :: (Ord a) => [a] -> [a]
  2. quicksort [] = []
  3. quicksort (x:xs) =
  4. let smallerSorted = quicksort (filter (<=x) xs)
  5. biggerSorted = quicksort (filter (>x) xs)
  6. in smallerSorted ++ [x] ++ biggerSorted

在引haskell中fold后代码可以更加简洁和高效:

  1. (define (foldl f init xs)
  2. (define (iter xs acc)
  3. (if (null? xs) acc
  4. (iter (cdr xs) (f acc (car xs)))))
  5. (iter xs init))
  6. (define (foldr f init xs)
  7. (define (iter xs acc)
  8. (if (null? xs) acc
  9. (iter (cdr xs) (f (car xs) acc))))
  10. (iter (reverse xs) init))
  11. (define (qsort l greater)
  12. (if (not (pair? l)) '()
  13. (let ([m (car l)]
  14. [partition (foldr (lambda (x acc)
  15. (let ([small (car acc)]
  16. [large (cadr acc)])
  17. (if (greater x m) (list small (cons x large))
  18. (list (cons x small) large))))
  19. '(()()) (cdr l))])
  20. (append (qsort (car partition) greater)
  21. (cons m (qsort (cadr partition) greater))))))

冒泡排序

冒泡排序的详细介绍

首先要定义一个交换函数:

  1. ;交换列表中的两个元素
  2. (define (swap xs n1 n2)
  3. (let ([a (element-at xs n1)]
  4. [b (element-at xs n2)])
  5. (reverse (car (cdr (foldl (lambda (acc x)
  6. (let ([fst (car acc)]
  7. [snd (car (cdr acc))])
  8. (cond [(= fst n1) (list (+ fst 1) (cons b snd))]
  9. [(= fst n2) (list (+ fst 1) (cons a snd))]
  10. [else (list (+ fst 1) (cons x snd))]))) '(1 ()) xs))))))

以下是冒泡排序的实现:

  1. (define (bubble xs)
  2. (define (bubble-imp xs less)
  3. (if (= (length xs) 1) (list (car xs) less);返回最大值和剩余值组成的列表
  4. (let ([f (car xs)]
  5. [s (cadr xs)])
  6. (if (> f s) (bubble-imp (cdr (swap xs 1 2)) (reverse (cons s less)))
  7. (bubble-imp (cdr xs) (reverse (cons f less)))))))
  8. (define (iter xs result)
  9. (if (null? xs) result
  10. (let ([r (bubble-imp xs '())])
  11. (iter (cadr r) (cons (car r) result)))))
  12. (iter xs '()))

辅助过程bubble-imp用于筛选列表,它的返回值是输入列表的(最大元素 其余剩余元素的列表)

bubble-imp每轮执行都会比较列表的第一和第二个元素,如果第一个元素大于第二个元素则交换它们两的位置,

然后将较小的元素插入less中,之后丢弃表头(较小的元素)用剩余元素执行第二轮迭代,直到输入列表中只剩下1个元素,此时,那个剩余元素就是初始

输入列表中的最大元素,而less中则存放了其余的元素.

也就是每次执行bubble-imp都会生成一个最大值和其余元素的列表,为了完成排序需要将最大值插入结果列表,然后继续从剩余元素中找出次大值.

'iter'过程完成的就是这个任务,执行bubble-imp将最大值插入结果列表然后判断是否还有剩余元素,如果有则继续上述过程.

相应的haskell实现

  1. -- 冒泡排序
  2. bubble :: (Ord a) => [a] -> [a]
  3. bubble [] = error "Can't call pass on an empty list, dummy!"
  4. bubble (x:[]) = [x]
  5. bubble xs = iter xs []
  6. where
  7. pass xs left
  8. | size == 2 = if first < second then (first:left,second)
  9. else (second:left,first)
  10. | size > 2 = let remain = tail (tail xs) in
  11. if first < second then pass (second:remain) (first:left)
  12. else pass (first:remain) (second:left)
  13. | size == 1 = ([],first)
  14. where
  15. size = length xs
  16. first = head xs
  17. second = head (tail xs)
  18. iter xs result =
  19. let
  20. passret = (pass xs [])
  21. left = fst passret
  22. max = snd passret
  23. in
  24. if length left == 0 then (max:result)
  25. else iter left (max:result)

TSPL学习笔记(3):排序算法练习的更多相关文章

  1. STL学习笔记(排序算法)

    STL提供了好几种算法对区间内的元素排序.出来完全排序外,还支持局部排序. 对所有元素排序 void sort(RandomAccessIterator beg,RandomAccessIterato ...

  2. js学习笔记之排序算法的原理及代码

    冒泡排序 比较任何两个相邻的项,如果第一个比第二个大,则交换它们 重复这样的操作,直到排序完成,具体代码如下: let arr = [67,23,11,89,45,76,56,99] function ...

  3. Java基础复习笔记基本排序算法

    Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ...

  4. GMM高斯混合模型学习笔记(EM算法求解)

    提出混合模型主要是为了能更好地近似一些较复杂的样本分布,通过不断添加component个数,能够随意地逼近不论什么连续的概率分布.所以我们觉得不论什么样本分布都能够用混合模型来建模.由于高斯函数具有一 ...

  5. 【C语言编程入门笔记】排序算法之快速排序,一文轻松掌握快排!

    排序算法一直是c语言重点,各个算法适应不用的环境,同时,在面试时,排序算法也是经常被问到的.今天我们介绍下快速排序,简称就是快排. 1.快速排序思想: 快排使用 分治法 (Divide and con ...

  6. 强化学习-学习笔记7 | Sarsa算法原理与推导

    Sarsa算法 是 TD算法的一种,之前没有严谨推导过 TD 算法,这一篇就来从数学的角度推导一下 Sarsa 算法.注意,这部分属于 TD算法的延申. 7. Sarsa算法 7.1 推导 TD ta ...

  7. 《算法导论》读书笔记之排序算法—Merge Sort 归并排序算法

    自从打ACM以来也算是用归并排序了好久,现在就写一篇博客来介绍一下这个算法吧 :) 图片来自维基百科,显示了完整的归并排序过程.例如数组{38, 27, 43, 3, 9, 82, 10}. 在算法导 ...

  8. C语言笔记 13_排序算法

    排序算法 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序(如从大到小.首字母从A到Z)错误就把他们交换过来. 过程 ...

  9. 【学习笔记】 Adaboost算法

    前言 之前的学习中也有好几次尝试过学习该算法,但是都无功而返,不仅仅是因为该算法各大博主.大牛的描述都比较晦涩难懂,同时我自己学习过程中也心浮气躁,不能专心. 现如今决定一口气肝到底,这样我明天就可以 ...

随机推荐

  1. 省市区县镇级联数据JS版

    前言:网站开发经常会涉及到报名,报名通常就会有地区级联的要求.如下所示.做这个功能就必须要有数据支撑.昨天努力了一天,从网上鼓捣了一份数据.分享下.纯技术性分享,非盈利的.如果有侵权的地方请知会,马上 ...

  2. Data层相关问题 & JS循环取值

    第一次写博客,里面是自己工作中碰到的问题及总结的知识点,便于自己以后回顾,技术大牛们请直接忽略这篇文章,也希望能帮助到想我这样的小白! Data层相关问题总结: 1. 代码管理用的是 VSS 2005 ...

  3. 配置ubuntu 14.04.3 LTS odoo 9.0开发环境

    使用VMware Fusion 8.0.1创建ubuntu 64bit虚拟机:使用ubuntu-14.04.3-desktop-amd64.iso镜像缺省安装ubuntu,用户名odoo,密码1234 ...

  4. Winform(C#.NET)自动更新组件的使用及部分功能实现(续)

    接昨天的文章Winform(C#.NET)自动更新组件的使用及部分功能实现 强制更新的实现部分: 将DownloadConfirm窗体修改成单纯的类 public class DownloadConf ...

  5. 用VS连接oracle数据库时ORA-12504错误

    在用VS2008连接oracle数据库时,可能会出现: ORA-12504: TNS: 监听程序在 CONNECT_DATA 中未获得 SERVICE_NAME 只需在web.config文件Data ...

  6. 【Leetcode】【Medium】Group Anagrams

    Given an array of strings, group anagrams together. For example, given: ["eat", "tea& ...

  7. Flex开发一周年感悟

    优点: 1.Flex上手简单,与html和js很像,是一种web前端语言,对于简单的界面.图表.交互都有不错的封装.它能够让新手在短时间内开发出比较有模样的项目. 2.有很多第三方api可以使用,如a ...

  8. WinDbg 命令三部曲:(三)WinDbg SOSEX 扩展命令手册

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...

  9. 【转】URL的井号

    去年9月,twitter改版. 一个显著变化,就是URL加入了"#!"符号.比如,改版前的用户主页网址为 http://twitter.com/username 改版后,就变成了 ...

  10. shellKali Linux Web 渗透测试— 初级教程(第三课)

    shellKali Linux Web 渗透测试— 初级教程(第三课) 文/玄魂 目录 shellKali Linux Web 渗透测试—初级教程(第三课) 课程目录 通过google hack寻找测 ...