У меня есть набор входных последовательностей (представленных в виде списков), для каждой из которых я генерирую набор всех ее подпоследовательностей (также списки ). Эти подпоследовательности хранятся как ключи в хеш-таблице EQUAL и никогда не удаляются и не модифицируются сборщиком мусора (однако связанные значения изменяются).
Моя проблема в том, что метод, который я сейчас использую для достижения этой цели, использует гораздо больше места в куче, чем мне хотелось бы.
Чтобы было понятно, о чем я говорю, предположим, что у нас есть последовательность:
#1=(A B C D)
Подпоследовательности:
#2=()
#3=(A)
#4=(A B)
#5=(A B C)
#6=(A B C D)
#7=(B)
#8=(B C)
#9=(B C D)
#10=(C)
#11=(C D)
#12=(D)
Следующий код, который я признаю не очень хорошим, создает этот набор (за исключением пустого подпоследовательность, о которой я на самом деле не забочусь):
(defun subseqs-of-length (length sequence)
(if (< (length sequence) length)
nil
(loop for start from 0 to (- (length sequence) length)
collect (subseq sequence start (+ start length)))))
(defun subseqs-of-length-< (length sequence)
(loop for len from 1 to (1- length)
append (subseqs-of-length len sequence)))
(defun all-subseqs (sequence)
(subseqs-of-length-< (1+ (length sequence)) sequence))
Как вы, вероятно, можете себе представить, при большом количестве входных последовательностей это занимает огромное количество кучи.
Самый очевидный способ сэкономить память, который я могу придумать, — это совместно использовать структуру списка; например, вы можете построить список 11 с помощью (cons 'c '#12#)
, список 9 с помощью (cons 'b '#11#)
, список 8 с помощью (cons 'b '#10#
и т. д. Было бы еще лучше, если бы вывод нескольких вызовов all-subseqs
мог совместно использовать структуру. Но я не могу придумать элегантного способа написать это.
У меня двоякий вопрос:
all-subseqs
, чтобы его результаты имели такую же структуру?