利用hashtable和time函数加速Lisp程序
程序功能是从一个英文文本中得到单词表,再得到押韵词表。即输出可能这样开始:
a ameoeba alba samba marimba...
这样结束:
...megahertz gigahertz jazz buzz fuzz
有了这么一个表,诗人会爽很多。
算法:得到单词表后,先把单词反序,用sort函数对所有反序单词排序,排好后再反序。
我叽里呱啦地写完了,用了630KB的2100行的文本来测试一下。time一下main函数,30多秒……现在用了如题的两个工具,程序跑到了0.08s!
首先,我处理重复单词的算法超级低效,先是在read-word函数里,不管是否当前单词已记录,都把当前单词记录下来,然后:
(setf words (delete-duplicates words :test #'equal :end n))
用delete-duplicates函数只保留相同单词的最后一个。
该函数的工作原理是两个两个比较,然后把前者丢弃掉,如果:from-end是true的话,那把后者丢弃掉。显然的是,它要比较很多,如果一个单词重复很多次的话,那要经过很多轮的比较,元素移动很多。具体是如何经过很多轮的、为什么很慢的,我也不懂,望高手指点。
如果我在添加新单词的时候:
(when (not (find word words :test #'string-equal))
(vector-push-extend word words 10000)
(incf n))
单词不存在的时候才加入。这样一来,程序就飞到了4s。
我是怎么知道delete-duplicates这里慢了呢?高手可以静态分析……当然,很容易猜错,分析失误。
(defun main ()
(defvar n)
(time (setf n (read-word "source.txt")))
(time (setf words (delete-duplicates words :test #'equal :end n)))
(time (reverse-words words))
(time (sort words #'string< #'nreverse))
(time (reverse-words words))
(time (write-word "rhymes.txt")))
这样子给每个函数time一下。在c++中,即是clock()/CLOCKS_PER_SEC。有了它,就是为啥“过早优化是一切罪恶的根源”。非常令我惊讶的是,一开始总共37s的时间,36s耗在 delete-duplicates上。按道理来说,我应该用36/37的优化时间都花在这部分。如果过早优化的话,一方面浪费时间在无关痛痒的优化上;另一方面,过早优化,代码更复杂,使得后面越来越难以修改,也容易多错误。所以,面对一问题,应该尽快地捣鼓出简单的第一版,之后再考虑优化。
接下来,用hash-table来记录单词,像这样
(defparameter ht (make-hash-table :test #'equal :size 10000))
(when (not (gethash word ht))
(setf (gethash word ht) t)
(vector-push-extend word words 10000))
这样就优化到了0.08s。
另外,在处理的过程中,不希望有那么多中间数组,故用map-into,像这样
(map-into seq fn seq)
函数fn对seq的每一个元素调用后结果保存到seq中。
希望数组v每个数都加1可写成:
(setf v (map-into v #'1+ v))
所以,最终我把反序、排序、再反序、输出,写成了这样:
(defun xform (fn seq)
(map-into seq fn seq))
(defun write-word (to)
(with-open-file (str to :direction :output
:if-exists :supersede)
(map nil #'(lambda (x)
(fresh-line str)
(princ x str))
(xform #'nreverse
(sort (xform #'nreverse words)
#'string<)))))
事实上,这照搬了《Ansi Common Lisp》的代码。
代码见:https://github.com/lzwjava/rhymes
利用hashtable和time函数加速Lisp程序的更多相关文章
- 给Lisp程序员的Python简介
给Lisp程序员的Python简介 作者:Peter Norvig,译者:jineslong<zzljlu@gmail.com> 这是一篇为Lisp程序员写的Python简介(一些Pyth ...
- 小议common lisp程序开发流程 - Ever 17 - 博客频道 - CSDN.NET
小议common lisp程序开发流程 - Ever 17 - 博客频道 - CSDN.NET 小议common lisp程序开发流程 分类: lisp 2011-04-17 20:59 1316人阅 ...
- [转载]高效使用matlab之四:一个加速matlab程序的例子
原文地址:http://www.bfcat.com/index.php/2012/11/speed-up-app/ 这篇文章原文是matlab网站上的,我把它翻译过来同时自己也学习一下.原文见这里 这 ...
- 用Cython加速Python程序以及包装C程序简单测试
用Cython加速Python程序 我没有拼错,就是Cython,C+Python=Cython! 我们来看看Cython的威力,先运行下边的程序: import time def fib(n): i ...
- 利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe)
原文:利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe) 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了.这 ...
- 利用InstallShiled 10.5制作AE应用程序安装包
[转]利用InstallShiled 10.5制作AE应用程序安装包 作者:3SNEWS 社区ESRI(ArcGIS)版版主:zhaoxiang_whuhttp://www.3snews.net/bb ...
- 使用RawComparator加速Hadoop程序
使用RawComparator加速Hadoop程序 在前面两篇文章[1][2]中我们介绍了Hadoop序列化的相关知识,包括Writable接口与Writable对象以及如何编写定制的Writable ...
- [05] 通过P/Invoke加速C#程序
通过P/Invoke加速C#程序 任何语言都会提供FFI机制(Foreign Function Interface, 叫法不太一样), 大多数的FFI机制是和C API. C#提供了P/Invoke来 ...
- 利用Gitee转接GitHub下载加速 简简单单 - 快快乐乐
利用Gitee转接GitHub下载加速 简简单单 - 快快乐乐 JERRY_Z. ~ 2020 / 10 / 26 转载请注明出处!️ 目录 利用Gitee转接GitHub下载加速 简简单单 - 快快 ...
随机推荐
- LA 3029 - City Game (简单扫描线)
题目链接 题意:给一个m*n的矩阵, 其中一些格子是空地(F), 其他是障碍(R).找一个全部由F 组成的面积最大的子矩阵, 输出其面积乘以3的结果. 思路:如果用枚举的方法,时间复杂度是O(m^2 ...
- bzoj4048 3928
羞耻,分组赛上考的,竟然没想出来, 对坐标离散化后区间dp即可,竟然还双倍经验 ; ..,..] of longint; v:..] of longint; a,b,h:..] of longint; ...
- UVa 11054 Wine trading in Gergovia【贪心】
题意:给出n个等距离的村庄,每个村庄要么买酒,要么卖酒,买酒和卖酒的总量相等, 把k个单位的酒从一个村庄运送到相邻的村庄,需要耗费k个单位劳动力,问怎样运送酒使得耗费的劳动力最少 买 卖 ...
- Android 开发问题集合
1.屏幕横.竖切换 修改“AndroidManifest.xml”的android:screenOrientation 一般需要:landscape.portrait 2.修改应用名字 修改“Andr ...
- UVA 658 It's not a Bug, it's a Feature! (最短路,经典)
题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了: ...
- 05day2
05day1 没什么可说,一道模拟水题,两道裸的模板题.05day2 是几天以来最难的一次. 圆排列 动态规划 [问题描述] 有 N 个人顺时针围在一圆桌上开会,他们对身高很敏感. 因此决定想使得 ...
- 用ffmpeg把H264数据流解码成YUV420P
在网上找了很久这方面的内容,发现网上的代码都太旧了,所使用的函数旧到连最新版本的ffmpeg都已经不包含了,所以对于我这个初学者来说太坑拉.不过经过多次查找ffmpeg的头文件和结合网上的内容,终于成 ...
- 搜集的一些RTMP项目,有Server端也有Client端
查询一些RTMP的协议封装时找到了一些RTMP开源项目,在这里列举一下,以后有时间或是有兴趣可以参考一下: just very few of them. Red5 only contains a se ...
- w3c盒子模型与ie盒子模型
盒子模型是css的专有名词,用来描述页面设置中的各种属性,如内容(content).填充(padding).边框(border).边界(margin),由于这些属性拼在一起,与日常生活中的“盒子”很相 ...
- Android 版本自动更新
截图如下: 代码实现如下: package com.update.apk; import java.io.BufferedReader; import java.io.File; import jav ...