zoukankan      html  css  js  c++  java
  • 利用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
     

  • 相关阅读:
    01、python数据分析与机器学习实战——python数据分析处理库Pandas
    01、python数据分析与机器学习实战——python数据分析处理库Pandas
    01、python数据分析与机器学习实战——python数据分析处理库Pandas
    从显示一张图片开始学习OpenGL ES
    从显示一张图片开始学习OpenGL ES
    C#中【pdb】文件
    C#中【pdb】文件
    SQLServer 中的存储过程中判断临时表是否存在,存在则删除临时表
    SQLServer 中的存储过程中判断临时表是否存在,存在则删除临时表
    C# 网络编程之webBrowser乱码问题及解决知识
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3367583.html
Copyright © 2011-2022 走看看