Etki alanı büyüklüğü küçük (| D | ~ 20) ve aralık daha büyük (f = D -> R), f: D -> R işlevlerinin tümünde bir dal ve sınır araması yapmaya çalışıyorum. ). Başlangıçta, aşağıdaki çözümü buldum.
(builder (domain range condlist partial-map)
(let ((passed? (check condlist partial-map)))
(cond
((not passed?) nil)
(domain (recur-on-first domain range condlist partial-map '()))
(t partial-map))))
(recur-on-first (domain range condlist partial-map ignored)
(cond
((null range) nil)
(t (let ((first-to-first
(builder (cdr domain)
(append ignored (cdr range))
condlist
(cons (cons (car domain) (car range)) partial-map))))
(or first-to-first
(recur-on-first domain
(cdr range)
condlist
partial-map
(cons (car range) ignored))))))))
Burada condlist
işleve parametre , builder
bir çözüm tarafından yerine getirilmesi gereken koşulların bir listesidir. İşlev check
, listedeki herhangi bir öğenin sıfırlanması durumunda döndürülür partial-map
. İşlev recur-on-first
, alandaki ilk öğeyi aralıktaki ilk öğeye atar ve oradan bir çözüm oluşturmaya çalışır. Bunu başaramamak recur-on-first
, etki alanındaki ilk öğeyi aralıktaki ilk öğeden başka bir öğeye atayan bir çözümü denemeye ve yapmaya çalışır. Ancak, ignored
bu atılan öğeleri (aralıktaki ilk öğe gibi) etki alanındaki diğer bazı öğelerin görüntüleri olabileceği için saklayan bir liste tutmalıdır.
Bu çözümle görebileceğim iki sorun var. Birincisi, listelerin ignored
ve range
işlevlerin recur-on-first
oldukça büyük olması ve append
bunların yapılması pahalı bir işlemdir. İkinci sorun, çözümün özyineleme derinliğinin aralığın büyüklüğüne bağlı olmasıdır.
Bu yüzden, aralıkları öğelerinde saklamak için çift bağlantılı listeleri kullanan aşağıdaki çözümü buldum. Fonksiyonlar start
, next
ve end
iki kat bağlantılı liste yineleme için olanaklar sunmaktadır.
(builder (domain range condlist &optional (partial-map nil))
(block builder
(let ((passed? (check condlist partial-map)))
(cond
((not passed?) nil)
(domain (let* ((cur (start range))
(prev (dbl-node-prev cur)))
(loop
(if (not (end cur))
(progn
(splice-out range cur)
(let ((sol (builder (cdr domain)
range
condlist
(cons (cons (car domain) (data cur)) partial-map))))
(splice-in range prev cur)
(if sol (return-from builder sol)))
(setq prev cur)
(setq cur (next cur)))
(return-from builder nil)))))
(t partial-map))))))
İkinci çözümün çalışma zamanı, ilk çözümün çalışma zamanından çok daha iyidir. append
Birinci çözelti içinde işlem ve bir çift bağlantılı liste üzerinden birleştirme elemanları ile ikame edilmektedir (bu işlemler zaman sabiti) ve yineleme derinliği sadece alanının büyüklüğüne bağlıdır. Ancak bu çözüm ile ilgili sorunum C
stil kodu kullanmasıdır. İşte benim sorum bu.
İkinci çözüm kadar verimli olan ancak setf
s ve değişken veri yapıları kullanmayan bir çözüm var mı ? Başka bir deyişle, bu soruna etkili bir işlevsel programlama çözümü var mı?