TSPL学习笔记(3):排序算法练习
快速排序
快排的详细介绍见,简单的说就是取输入序列中的首元素m,然后将除首元素m以外的其它元素分成两组,小于等于m的一组和大于m的一组.将3组元素组合成输入队列:小于等于m + m + 大于m.
下面看一个用haskell实现的快速排序代码:
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
haskell中有列表解析(List Comprehension)的支持,所以smallerSorted和biggerSorted两个集合通过列表解析很方便的就生成了.而Scheme中没有列表解析,所以首先要实现一个类似列表解析的功能将附后条件的列表元素筛选出来:
(define my-filter
(lambda (f l)
(define iter
(lambda (l a)
(if (not (pair? l)) a
(let* ([h (car l)] [r (if (f h) (append a (list h)) a)])
(iter (cdr l) r)))))
(iter l '())))
filter的功能是输入一个条件判断函数f和一个列表l,filter将l中所有满足f的元素组成一个列表并返回.上面代码使用的是accumulator模式,也就是在迭代模式,通过传进一个a参数在每次递归调用中保存结果.可以注意到这个filter的定义是满足尾递归的.
下面是filter的递归版本:
(define my-filter
(lambda (f l)
(if (not (pair? l)) '()
(let ([h (car l)])
(if (f h) (cons h (filter f (cdr l)))
(filter f (cdr l)))))))
通过cps变换将上述函数转换成尾递归的:
(define my-filter
(lambda (f l)
(define cps
(lambda (l k)
(if (not (pair? l)) (k '())
(let ([h (car l)])
(if (f h) (cps (cdr l) (lambda (x) (k (cons h x))))
(cps (cdr l) (lambda (x) (k x))))))))
(cps l (lambda (x) x))))
有了filter之后我们就可以实现qsort了:
(define qsort
(lambda (l)
(if (not (pair? l)) '()
(let* ([m (car l)]
[large (my-filter (lambda (x) (if (> x m) #t #f)) (cdr l))]
[less (my-filter (lambda (x) (if (<= x m) #t #f)) (cdr l))])
(append (qsort less) (cons m (qsort large)))))))
>(qsort `(5 1 4 2 3 3 7)) -> (1 2 3 3 4 5 7)
比较下与haskell版的区别,首先是没有列表解析,其次是没有模式匹配,需要用if表达式处理.
当然haskell中也是由filter的,下面就是haskell快排的filter版本:
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort (filter (<=x) xs)
biggerSorted = quicksort (filter (>x) xs)
in smallerSorted ++ [x] ++ biggerSorted
在引haskell中fold后代码可以更加简洁和高效:
(define (foldl f init xs)
(define (iter xs acc)
(if (null? xs) acc
(iter (cdr xs) (f acc (car xs)))))
(iter xs init))
(define (foldr f init xs)
(define (iter xs acc)
(if (null? xs) acc
(iter (cdr xs) (f (car xs) acc))))
(iter (reverse xs) init))
(define (qsort l greater)
(if (not (pair? l)) '()
(let ([m (car l)]
[partition (foldr (lambda (x acc)
(let ([small (car acc)]
[large (cadr acc)])
(if (greater x m) (list small (cons x large))
(list (cons x small) large))))
'(()()) (cdr l))])
(append (qsort (car partition) greater)
(cons m (qsort (cadr partition) greater))))))
冒泡排序
冒泡排序的详细介绍见
首先要定义一个交换函数:
;交换列表中的两个元素
(define (swap xs n1 n2)
(let ([a (element-at xs n1)]
[b (element-at xs n2)])
(reverse (car (cdr (foldl (lambda (acc x)
(let ([fst (car acc)]
[snd (car (cdr acc))])
(cond [(= fst n1) (list (+ fst 1) (cons b snd))]
[(= fst n2) (list (+ fst 1) (cons a snd))]
[else (list (+ fst 1) (cons x snd))]))) '(1 ()) xs))))))
以下是冒泡排序的实现:
(define (bubble xs)
(define (bubble-imp xs less)
(if (= (length xs) 1) (list (car xs) less);返回最大值和剩余值组成的列表
(let ([f (car xs)]
[s (cadr xs)])
(if (> f s) (bubble-imp (cdr (swap xs 1 2)) (reverse (cons s less)))
(bubble-imp (cdr xs) (reverse (cons f less)))))))
(define (iter xs result)
(if (null? xs) result
(let ([r (bubble-imp xs '())])
(iter (cadr r) (cons (car r) result)))))
(iter xs '()))
辅助过程bubble-imp用于筛选列表,它的返回值是输入列表的(最大元素 其余剩余元素的列表)
bubble-imp每轮执行都会比较列表的第一和第二个元素,如果第一个元素大于第二个元素则交换它们两的位置,
然后将较小的元素插入less中,之后丢弃表头(较小的元素)用剩余元素执行第二轮迭代,直到输入列表中只剩下1个元素,此时,那个剩余元素就是初始
输入列表中的最大元素,而less中则存放了其余的元素.
也就是每次执行bubble-imp都会生成一个最大值和其余元素的列表,为了完成排序需要将最大值插入结果列表,然后继续从剩余元素中找出次大值.
'iter'过程完成的就是这个任务,执行bubble-imp将最大值插入结果列表然后判断是否还有剩余元素,如果有则继续上述过程.
相应的haskell实现
-- 冒泡排序
bubble :: (Ord a) => [a] -> [a]
bubble [] = error "Can't call pass on an empty list, dummy!"
bubble (x:[]) = [x]
bubble xs = iter xs []
where
pass xs left
| size == 2 = if first < second then (first:left,second)
else (second:left,first)
| size > 2 = let remain = tail (tail xs) in
if first < second then pass (second:remain) (first:left)
else pass (first:remain) (second:left)
| size == 1 = ([],first)
where
size = length xs
first = head xs
second = head (tail xs)
iter xs result =
let
passret = (pass xs [])
left = fst passret
max = snd passret
in
if length left == 0 then (max:result)
else iter left (max:result)
TSPL学习笔记(3):排序算法练习的更多相关文章
- STL学习笔记(排序算法)
STL提供了好几种算法对区间内的元素排序.出来完全排序外,还支持局部排序. 对所有元素排序 void sort(RandomAccessIterator beg,RandomAccessIterato ...
- js学习笔记之排序算法的原理及代码
冒泡排序 比较任何两个相邻的项,如果第一个比第二个大,则交换它们 重复这样的操作,直到排序完成,具体代码如下: let arr = [67,23,11,89,45,76,56,99] function ...
- Java基础复习笔记基本排序算法
Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ...
- GMM高斯混合模型学习笔记(EM算法求解)
提出混合模型主要是为了能更好地近似一些较复杂的样本分布,通过不断添加component个数,能够随意地逼近不论什么连续的概率分布.所以我们觉得不论什么样本分布都能够用混合模型来建模.由于高斯函数具有一 ...
- 【C语言编程入门笔记】排序算法之快速排序,一文轻松掌握快排!
排序算法一直是c语言重点,各个算法适应不用的环境,同时,在面试时,排序算法也是经常被问到的.今天我们介绍下快速排序,简称就是快排. 1.快速排序思想: 快排使用 分治法 (Divide and con ...
- 强化学习-学习笔记7 | Sarsa算法原理与推导
Sarsa算法 是 TD算法的一种,之前没有严谨推导过 TD 算法,这一篇就来从数学的角度推导一下 Sarsa 算法.注意,这部分属于 TD算法的延申. 7. Sarsa算法 7.1 推导 TD ta ...
- 《算法导论》读书笔记之排序算法—Merge Sort 归并排序算法
自从打ACM以来也算是用归并排序了好久,现在就写一篇博客来介绍一下这个算法吧 :) 图片来自维基百科,显示了完整的归并排序过程.例如数组{38, 27, 43, 3, 9, 82, 10}. 在算法导 ...
- C语言笔记 13_排序算法
排序算法 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序(如从大到小.首字母从A到Z)错误就把他们交换过来. 过程 ...
- 【学习笔记】 Adaboost算法
前言 之前的学习中也有好几次尝试过学习该算法,但是都无功而返,不仅仅是因为该算法各大博主.大牛的描述都比较晦涩难懂,同时我自己学习过程中也心浮气躁,不能专心. 现如今决定一口气肝到底,这样我明天就可以 ...
随机推荐
- C#常用IO流与读写文件
.文件系统 ()文件系统类的介绍 文件操作类大都在System.IO命名空间里.FileSystemInfo类是任何文件系统类的基类:FileInfo与File表示文件系统中的文件:Directory ...
- Dynamic CRM 2013学习笔记(三十三)自定义审批流4 - 规则节点 -有分支的流程处理
上次介绍过节点的基本配置<Dynamic CRM 2013学习笔记(三十二)自定义审批流3 - 节点及实体配置>,这次介绍下规则节点,因为有时流程里会有一些分支.合并,这时就要用到规则节点 ...
- Dynamic CRM 2013学习笔记(四十二)流程5 - 实时/同步工作流(Workflow)用法图解
实时工作流跟插件一样,也是用事件执行管道来执行,能在pre,post或核心操作中执行.跟插件一样,不能在创建之前和删除之后执行.如果执行过程中有异常发生,会取消并回滚整个操作.实时工作流里所有的活动和 ...
- NABCD需求分析
1. N 需求 如今的社会,每个公司每个人都有大量的信息需要处理.保管和查询,这就难免会有些信息在个人电脑中保存的位置被遗忘,需要一款简单并且实用的搜索引擎来搜索个人 所需求的信息. 2. A ...
- windowsXP用户被禁用导致不能网站登录
1.查看系统事件,发现弹出如下的错误 2.根据上面的错误,我们很容易就可以判断是禁用了账户引起的 2.1后面进入计算机管理,再进入用户管理 2.2双击点开Internet来宾用于,发现此用户已经停用了 ...
- [C#] Timer + Graphics To Get Simple Animation (简单的源码例子,适合初学者)
>_<" 这是一个非常简单的利用C#的窗口工程创立的程序,用来做一个简单的动画,涉及Timer和Graphics,适合初学者,高手略过~
- struts2学习笔记之二:基本环境搭建
学习struts2有一段时间了,作为一个运维人员学习的时间还是挺紧张的,写这篇文件为了方便以后复习时使用 环境: MyEclipse 10 tomcat6 jdk1.6 首先建立一个web项目,并 ...
- 重学JAVA基础(八):锁的基本知识
1.线程状态 如上图,当我们新建一个线程,并start后,其实不一定会马上执行,因为只有操作系统调度了我们的线程,才能真正进行执行,而操作系统也随时可以运行其他线程,这时线程又回到可运行状态.这个过程 ...
- hdu4508 完全背包,湫湫系列故事——减肥记I
湫湫系列故事——减肥记I 对于01背包和完全背包,昨晚快睡着的时候,突然就来了灵感 区别:dp[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值 在第二重循环,01 是倒着循环的,因 ...
- OpenCV Linux 安装 Make出错
执行完CMake之后再执行make时遇到以下错误 [ %] Generating precomp.hpp.gch/opencv_core_Release.gch In file included /b ...