Dal ve sınırlamayı işlevsel bir programlama dilinde nasıl uygulayabilirim?


26

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 condlistişleve parametre , builderbir çö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, ignoredbu 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 ignoredve rangeişlevlerin recur-on-firstoldukça büyük olması ve appendbunları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, nextve endiki 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. appendBirinci çö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 Cstil kodu kullanmasıdır. İşte benim sorum bu.

İkinci çözüm kadar verimli olan ancak setfs 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ı?

Yanıtlar:


1

Akla gelen ilk fikir: aynı genel yaklaşımı kullanın, ancak döngüyü, hesaplamanın bir sonraki aşaması için parametresi eklenmiş liste olan bir özyinelemeli çağrı ile değiştirin. Eklenen listeyi hiçbir zaman değiştirmeniz gerekmez, her aşamada yalnızca yeni bir liste oluşturun. Kuşkusuz bu sürekli bir zaman değildir, ancak yine de nereye ekleyeceğinizi bulmak için listede yürümeniz gerekir. Özellikle tek başına bağlanmış bir liste kullanabilirseniz, düğümlerin çoğunu yeniden kullanabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.