एक कार्यात्मक प्रोग्रामिंग भाषा में एक शाखा-और-बाउंड को कैसे लागू किया जाए?


26

मैं सभी कार्यों के सेट पर एक शाखा और बाध्य खोज लिखने की कोशिश कर रहा हूँ f: D -> R, जहां डोमेन का आकार (- | D | ~ ~ 20) है और सीमा बहुत बड़ी है (| R | ~ 2 ^ 20 )। प्रारंभ में, मैं निम्नलिखित समाधान के साथ आया था।

(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))))))))

यहां condlistफ़ंक्शन builderका पैरामीटर उन स्थितियों की एक सूची है जिन्हें किसी समाधान द्वारा संतुष्ट किया जाना चाहिए। checkशर्तों की सूची में किसी भी तत्व का उल्लंघन होने पर फ़ंक्शन शून्य हो जाता है partial-map। फ़ंक्शन recur-on-firstडोमेन में पहले तत्व को सीमा में पहले तत्व को असाइन करता है और वहां से एक समाधान बनाने की कोशिश करता है। इस प्रक्रिया recur-on-firstको विफल करने के लिए खुद को हल करने का प्रयास करता है और एक समाधान का निर्माण करता है जो कि सीमा में पहले तत्व के अलावा किसी अन्य तत्व के लिए डोमेन में पहला तत्व प्रदान करता है। हालाँकि, इसे एक सूची को बनाए रखना होगा जो ignoredइन परित्यक्त तत्वों (जैसे श्रेणी में पहला तत्व) को संग्रहीत करता है क्योंकि वे डोमेन में कुछ अन्य तत्वों की छवियां हो सकती हैं।

दो समस्याएं हैं जो मैं इस समाधान के साथ देख सकता हूं। पहला यह है कि सूचियाँ ignoredऔर rangeफ़ंक्शन recur-on-firstबहुत बड़े हैं और appendउन्हें एक महंगा ऑपरेशन है। दूसरी समस्या यह है कि समाधान की पुनरावृत्ति गहराई सीमा के आकार पर निर्भर करती है।

इसलिए मैं निम्नलिखित समाधान के साथ आया, जो रेंज में तत्वों को संग्रहीत करने के लिए दोगुनी लिंक की गई सूचियों का उपयोग करता है। कार्य start, nextऔर endदोगुनी लिंक की गई सूची पर पुनरावृति करने के लिए सुविधाएं प्रदान करते हैं।

(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))))))

पहले समाधान के रनटाइम की तुलना में दूसरे समाधान का रनटाइम बहुत बेहतर है। appendपहले समाधान में आपरेशन में और एक दोगुना लिंक्ड सूची से बाहर स्प्लिसिंग तत्वों ने ले ली है (इन आपरेशनों लगातार समय कर रहे हैं) और प्रत्यावर्तन गहराई केवल डोमेन के आकार पर निर्भर करता है। लेकिन इस समाधान के साथ मेरी समस्या यह है कि यह Cस्टाइल कोड का उपयोग करता है। तो मेरा सवाल ये है।

क्या कोई ऐसा समाधान है जो दूसरे समाधान के रूप में कुशल है लेकिन setfs और परस्पर डेटा संरचनाओं का उपयोग नहीं करता है ? दूसरे शब्दों में, क्या इस समस्या का एक कुशल कार्यात्मक प्रोग्रामिंग समाधान है?

जवाबों:


1

पहला विचार जो मन में आता है: एक ही सामान्य दृष्टिकोण का उपयोग करें, लेकिन लूप को एक पूंछ-पुनरावर्ती कॉल के साथ बदलें जिसका पैरामीटर कंप्यूटेशन के अगले चरण के लिए spliced ​​सूची है? आपको कभी भी स्पाइस लिस्ट को संशोधित करने की आवश्यकता नहीं है, बस प्रत्येक चरण में एक नई सूची तैयार करें। यह माना जाता है कि यह निरंतर समय नहीं है, लेकिन आपको यह पता लगाने के लिए सूची में चलना होगा कि कहीं भी विभाजन करना है। यहां तक ​​कि यह अधिकांश नोड्स को फिर से उपयोग करने में सक्षम हो सकता है, खासकर यदि आप एक एकल-लिंक की गई सूची का उपयोग कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.