写快速排序几乎是很多人被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:写一个漂亮的快排相关推荐

  1. 用纯Python就能写一个漂亮的网页

    我们在写一个网站或者一个网页界面的时候,需要学习很多东西,对小白来说很困难!比如我要做一个简单的网页交互: 要懂后端,比如Python里面的Django或者Flask,或者是Java里面的Spring ...

  2. 再见HTML ! 用纯Python就能写一个漂亮的网页

    我们在写一个网站或者一个网页界面的时候,需要学习很多东西,对小白来说很困难!比如我要做一个简单的网页交互: 要懂后端,比如Python里面的Django或者Flask,或者是Java里面的Spring ...

  3. 写一个漂亮的登录界面

    好的,我会尽力为您提供一个漂亮的登录界面的设计建议. 首先,我们可以在界面的上方设置一个清晰的标题栏,标题栏中可以包含网站的 logo 和名称. 然后,在界面的中间部分,我们可以设置一个表单来让用户输 ...

  4. 如何使用 markdown 写一个漂亮的简历(带排版和布局)

    最近网上比较流行的使用 markdown 写简历,经过我对比和实战,找到一个比较好操作的,特分享一下 感谢老哥开源的代码 https://github.com/xzk1990314/nimo-mark ...

  5. PhpExcel 写一个漂亮的表格

    文章不长,文章不长,文章不长 本表格是模仿橙心优选团长面单来做的 先上表格 思路 确定总共有多少列,需要确定表头要合并多少单元格,可以多预留 1~2 列,如果用不到,最后把宽度设置为 0 剩下的就是合 ...

  6. python算法题排序_python-数据结构与算法- 面试常考排序算法题-快排-冒泡-堆排-二分-选择等...

    算法可视化网站推荐---->visualgo 0.面试题中的排序算法 一些排序算法可能在工作中用的会比较少,但是面试却是不得不面对的问题.算法有助于提高我们对数据结构的理解以及提高自己的逻辑能力 ...

  7. 写一个饿汉单例模式的例子_你写的单例模式,能防止反序列化和反射吗?

    推荐学习 "23种设计模式知识要点"都没读通过,还有脸说摸不清搞不懂? 玩转JAVA筑基之Netty.并发编程与设计模式,打好基础备战春招 前言 说起单例模式,相信大家都不会陌生. ...

  8. java快排原理_Java数据结构与算法——快速排序

    声明:码字不易,转载请注明出处,欢迎文章下方讨论交流. 前言:Java数据结构与算法专题会不定时更新,欢迎各位读者监督.本篇文章介绍排序算法中最常用也是面试中最容易考到的排序算法--快排,包括快排的思 ...

  9. 排序算法--快排的优化

    排序算法–快排的优化 下面是我写的一种快排: #include <iostream> #include <stdlib.h>using namespace std;void P ...

最新文章

  1. 操作系统就是一个“死循环”?
  2. python编程100例头条-今日头条python面试题之编程篇
  3. 用Redis快速实现BloomFilter!
  4. 深度学习100例-卷积神经网络(CNN)识别神奇宝贝小智一伙 | 第16天
  5. 一个对复用view下滑动流畅度优化,图片和内存处理,稳定性都非常强大的android开源框架(beyondPhysics)...
  6. docker 打包镜像_Spring Boot2 系列教程(四十一)部署 Spring Boot 到远程 Docker 容器
  7. java 获取方法_Java 反射理解(三)-- Java获取方法信息
  8. mysql 线程id_查找MySQL线程中死锁的ID的方法
  9. php获取localstorage的值,localStorage的设置和取值Demo
  10. oracle取月去0,Oracle取月份,不带前面的0
  11. hbase启动后HMaster进程自动关闭
  12. tp5调用阿里云短信接口
  13. 访问限制:由于对必需的库E:\j2sdk\jre\lib\rt.jar具有一定限制,因此无法访问类型JFrame
  14. QQ空间FLASH代码及其使用方法
  15. ffmpeg将多个MP4合并成一个MP4
  16. 室内定位蓝牙信标安装规划问题
  17. 练习篇:完整实践——实现一个简易日记本应用
  18. 帅气的团队介绍HTML源码
  19. Android VR入门文章
  20. 幻灯片批量添加角标_如何在Google文档或幻灯片中设置上标或下标文本的格式

热门文章

  1. 微信公众平台开发消息回复总结
  2. 抖音四面被拒,再战头条终获offer,系列教学
  3. 利用Windbg分析高内存占用问题
  4. dateutil 日期计算_java计算两个日期之间的天数
  5. 【游戏建模全流程】在Maya中制作赛博朋克风格场景
  6. JML规格单元梳理总结
  7. MOSS 2007 性能及容量规划
  8. ppt转pdf在线转换
  9. 计算机网络 DNSSEC原理
  10. 想搭建自己的网站,应该从哪处入手呢?选择什么样配置的服务器捏?通过哪些手段赚取足够的维护网