lisp-trie数据结构中函数(内存)的优化

lisp-trie数据结构中函数(内存)的优化,lisp,trie,Lisp,Trie,我是一名lisp初学者,我正在尝试编写一个包,为trie定义一个类,并将整个拼字词典读入其中。结构充当一个节点,每个节点都有一个关联列表,用于跟踪来自它的字母(指向其他子序列) 这是我的课程代码 (DEFCLASS n-trie () ((word :accessor word :initform 'nil :initarg :word) (word-count :accessor wcount :initform 0

我是一名lisp初学者,我正在尝试编写一个包,为trie定义一个类,并将整个拼字词典读入其中。结构充当一个节点,每个节点都有一个关联列表,用于跟踪来自它的字母(指向其他子序列)

这是我的课程代码

(DEFCLASS n-trie ()
  ((word :accessor word
         :initform 'nil
         :initarg :word)
   (word-count :accessor wcount
               :initform 0
               :initarg :wcount)
   (next-letters :accessor next-letters
                 :initform 'nil
                 :initarg :next-letters)))
这是我的addword函数

(defun add-word (string trie) ;;iterative method for looping through string
  (let ((s (coerce string 'list))
        (tri trie))
    (dolist (item s)
      (cond
       ((assoc item (next-letters tri))
        (incf (wcount tri))
        (setf tri (cdr (assoc item (next-letters tri)))))
       (t
        (incf (wcount tri))
        (setf (next-letters tri) (acons item (make-instance 'n-trie) (next-letters tri)))
        (setf tri (cdr (assoc item (next-letters tri)))))))
    (setf (word tri) string)))
下面是打开我的文件(拼字字典)并读取每一行的函数

(defun read-words (file trie)
  (let((str (open file)))
    (labels ((rec (tri)
                  (let ((line (read-line str nil nil)))
                    (cond 
                     (line (add-word line tri)
                           (rec tri))
                     (t (close str)
                        trie)))))
      (rec trie))))
每当我试图加载整个字典时,就会出现堆栈溢出。拼字词典中有超过10万个单词,但在6000个单词时失败了……我的内存使用有问题,但我似乎不知道是什么

在这些定义中,我是否做了一些内在昂贵的内存方面的事情?我尝试将trie节点变成一个结构而不是一个类,并得到了类似的结果。我也有一个从字典中添加单词的递归算法,但它同样糟糕


我已经为此挣扎了好几个小时,我有点沮丧…

我要改变的第一件事是函数
读取单词。它使用尾部递归,与Scheme中的类似。这在Common Lisp中不是惯用的。使用
和-OPEN-FILE
打开文件,并使用循环结构读取行。如果公共Lisp系统没有优化尾部递归,那么该递归已经在大型文本文件上创建了堆栈溢出

因此:

  • 不要使用尾部递归,如果不需要,并且您知道您的CL实现实际上支持并理解它。例如,高调试模式通常会阻止尾部递归优化

  • 与-OPEN-FILE一起使用
    。不要使用
    打开
    /
    关闭

  • 使用
    IF
    而不是
    COND
    ——特别是当我们处理正常的真/假谓词时


我开始尝试用哈希表实现。。。我认为a名单会更有效。这个实现的要点是单词中的每个字母都应该在一个单独的子trie中,只有当该字母的子trie分支不存在时才创建一个新的子trie。关于以某些子项结尾的单词以及子项下存在多少单词的信息也是目标的一部分(因此,我想通过拥有n-trie实例的关联列表来跟踪此信息。我同意这似乎不是存储信息的最有效方式……而且(下一个字母tri)只是访问(下几封信)n-trie类的属性…所以这不应该是一个很大的内存问题。每个键的哈希表中的值是多少?是另一个节点吗?否则如何遍历树?好的,我将暂时改变这个想法。如果有任何突破,我将报告。谢谢帮助!试用了您的实现,pret你确定你在做我想做的事情,但是我遇到了一个错误,堆空间用完了…我在使用allegro common lisp,你使用的是不同的解释器吗?谢谢,我会给你一个机会并报告回来。只是出于好奇…我一直认为在CL中使用cond比使用if更好…这似乎很好。谢谢。它还没有加载我的完整字典…我的allegro cl免费版已经达到了堆的极限。有什么建议吗?