Haskell:写一个漂亮的快排
写快速排序几乎是很多人被Haskell圈粉的第一瞬间,然而可能很多人一开始的实现并不是最优的。此处记录了我的心路历程。
文章目录
- 最初的实现
- 使用filter
- 只需要filter一次
- 优雅地解决问题
最初的实现
quick_sort :: Ord a => [a] -> [a]
quick_sort [] = []
quick_sort [x] = [x]
quick_sort xs = quick_sort [xs !! i | i <- [0..len-1], xs !! i <= mid_num && i /= half_pos] ++ [mid_num] ++ quick_sort [xs !! i | i <- [0..len-1], xs !! i > mid_num && i /= half_pos] where mid_num = xs !! half_poshalf_pos = floor $ fromIntegral (len / 2)len = length xs
使用filter
上面的代码存在两点可以改进的东西:
1.使用filter函数取得比中值小的所有数,语法比列表解析式更加简洁
2.如果数据是随机分布的,可以不必取中位元素,取开头元素即可
quick_sort :: Ord a => [a] -> [a]
quick_sort [] = []
quick_sort [x] = [x]
quick_sort xs = quick_sort (filter (< mid_num) xs)++ quick_sort (filter (== mid_num) xs)++ quick_sort (filter (> mid_num) xs)where mid_num = head xs
张淞老师的书里面写得更简单:
quick_sort :: Ord a => [a] -> [a]
quick_sort [] = []
quick_sort [x] = [x]
quick_sort (x:xs) = quick_sort (filter (<= x) xs)++ [x]++ quick_sort (filter (> x) xs)
只需要filter一次
进一步地,上面的算法每次分割对列表扫描2次(两次filter),但实际上一次就够了(两部分列表各为补集)。实现如下:
sep :: Ord a => a -> [a] -> ([a], [a])
sep _ [] = ([], [])
sep sep_num (x:xs) | x <= sep_num = ([x] ++ fst sep_xs, snd sep_xs)| otherwise = (fst sep_xs, [x] ++ snd sep_xs)where sep_xs = sep sep_num xsquick_sort :: Ord a => [a] -> [a]
quick_sort [] = []
quick_sort [x] = [x]
quick_sort (x:xs) = quick_sort (fst sep_tuple)++ [x]++ quick_sort (snd sep_tuple)where sep_tuple = sep x xs
优雅地解决问题
几个月后又回顾这段代码:
- 善用模式匹配!
(l, r)
的写法比fst, snd
的写法好很多。 - 善用标准库!
Data.List.partition
提供了sep
的功能,没必要reinvent - 对代码里面的冗余要敏锐!
quick_sort [x] = [x]
完全没有必要。 - 使用默认构造器提高效率!
[x]++xs
不如x:xs
效率高。
import Data.ListquickSort :: Ord a => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = quickSort l ++ (x : quickSort r) where (l, r) = partition (<x) xs
写好之后还要quickcheck一下成果:
import Test.QuickChecksorted :: Ord a => [a] -> Bool
sorted [] = True
sorted (x:[]) = True
sorted (x:y:xs) = x <= y && sorted (y:xs)prop_sort :: Ord a => [a] -> Bool
prop_sort xs = sorted (quickSort xs)
成功通过
*Main> :l sort.hs
[1 of 1] Compiling Main ( sort.hs, interpreted )
Ok, modules loaded: Main.
*Main> quickCheck prop_sort
+++ OK, passed 100 tests.
完整的代码
import Data.List (partition)
import Test.QuickCheck-- qsortquickSort :: Ord a => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = quickSort l ++ [x] ++ quickSort r where (l, r) = partition (<x) xssorted :: Ord a => [a] -> Bool
sorted [] = True
sorted (x:[]) = True
sorted (x:y:xs) = x <= y && sorted (y:xs)-- checkprop_sort :: Ord a => [a] -> Bool
prop_sort xs = sorted (quickSort xs)-- quickCheck prop_sort
Haskell:写一个漂亮的快排相关推荐
- 用纯Python就能写一个漂亮的网页
我们在写一个网站或者一个网页界面的时候,需要学习很多东西,对小白来说很困难!比如我要做一个简单的网页交互: 要懂后端,比如Python里面的Django或者Flask,或者是Java里面的Spring ...
- 再见HTML ! 用纯Python就能写一个漂亮的网页
我们在写一个网站或者一个网页界面的时候,需要学习很多东西,对小白来说很困难!比如我要做一个简单的网页交互: 要懂后端,比如Python里面的Django或者Flask,或者是Java里面的Spring ...
- 写一个漂亮的登录界面
好的,我会尽力为您提供一个漂亮的登录界面的设计建议. 首先,我们可以在界面的上方设置一个清晰的标题栏,标题栏中可以包含网站的 logo 和名称. 然后,在界面的中间部分,我们可以设置一个表单来让用户输 ...
- 如何使用 markdown 写一个漂亮的简历(带排版和布局)
最近网上比较流行的使用 markdown 写简历,经过我对比和实战,找到一个比较好操作的,特分享一下 感谢老哥开源的代码 https://github.com/xzk1990314/nimo-mark ...
- PhpExcel 写一个漂亮的表格
文章不长,文章不长,文章不长 本表格是模仿橙心优选团长面单来做的 先上表格 思路 确定总共有多少列,需要确定表头要合并多少单元格,可以多预留 1~2 列,如果用不到,最后把宽度设置为 0 剩下的就是合 ...
- python算法题排序_python-数据结构与算法- 面试常考排序算法题-快排-冒泡-堆排-二分-选择等...
算法可视化网站推荐---->visualgo 0.面试题中的排序算法 一些排序算法可能在工作中用的会比较少,但是面试却是不得不面对的问题.算法有助于提高我们对数据结构的理解以及提高自己的逻辑能力 ...
- 写一个饿汉单例模式的例子_你写的单例模式,能防止反序列化和反射吗?
推荐学习 "23种设计模式知识要点"都没读通过,还有脸说摸不清搞不懂? 玩转JAVA筑基之Netty.并发编程与设计模式,打好基础备战春招 前言 说起单例模式,相信大家都不会陌生. ...
- java快排原理_Java数据结构与算法——快速排序
声明:码字不易,转载请注明出处,欢迎文章下方讨论交流. 前言:Java数据结构与算法专题会不定时更新,欢迎各位读者监督.本篇文章介绍排序算法中最常用也是面试中最容易考到的排序算法--快排,包括快排的思 ...
- 排序算法--快排的优化
排序算法–快排的优化 下面是我写的一种快排: #include <iostream> #include <stdlib.h>using namespace std;void P ...
最新文章
- 操作系统就是一个“死循环”?
- python编程100例头条-今日头条python面试题之编程篇
- 用Redis快速实现BloomFilter!
- 深度学习100例-卷积神经网络(CNN)识别神奇宝贝小智一伙 | 第16天
- 一个对复用view下滑动流畅度优化,图片和内存处理,稳定性都非常强大的android开源框架(beyondPhysics)...
- docker 打包镜像_Spring Boot2 系列教程(四十一)部署 Spring Boot 到远程 Docker 容器
- java 获取方法_Java 反射理解(三)-- Java获取方法信息
- mysql 线程id_查找MySQL线程中死锁的ID的方法
- php获取localstorage的值,localStorage的设置和取值Demo
- oracle取月去0,Oracle取月份,不带前面的0
- hbase启动后HMaster进程自动关闭
- tp5调用阿里云短信接口
- 访问限制:由于对必需的库E:\j2sdk\jre\lib\rt.jar具有一定限制,因此无法访问类型JFrame
- QQ空间FLASH代码及其使用方法
- ffmpeg将多个MP4合并成一个MP4
- 室内定位蓝牙信标安装规划问题
- 练习篇:完整实践——实现一个简易日记本应用
- 帅气的团队介绍HTML源码
- Android VR入门文章
- 幻灯片批量添加角标_如何在Google文档或幻灯片中设置上标或下标文本的格式