2015-12-22 6 views
5

मैं लिस्प में एक सूची उल्टा करने के लिए कोशिश कर रहा हूँ में सूची पीछे है, लेकिन मैं त्रुटि मिलती है: "त्रुटि: अपवाद C0000005 [झंडे 0] 20303FF3 पर {ऑफसेट 25 # अंदर} eax 108 EBX 200925CA ECX 200 EDX 2EFDD4D esp 2EFDCC8 ईबीपी 2EFDCE0 ईएसआई 628 ईडीआई 628 "लिस्प

मेरे कोड इस प्रकार है:

(defun rev (l) 
    (cond 
     ((null l) '()) 
     (T (append (rev (cdr l)) (list (car l)))))) 

किसी को भी मुझे बता सकते हैं क्या मैं गलत कर रहा हूँ? अग्रिम में धन्यवाद!

+0

एक पूंछ पुनरावर्ती समारोह में परिवर्तित करने के लिए दृष्टिकोण एक संचायक, चर result निम्नलिखित में शुरू करना शामिल है मैं इसे "अन्यथा" शाखा के रूप में उपयोग कर रहा हूं, उसके बाद सभी शर्तों की जांच की गई .. – Nelly

+0

सामान्य लिस्प के लिए कार्य सही है। आप किस लिस्प का उपयोग कर रहे हैं? elisp? – Renzo

+0

लिस्पॉर्क्स व्यक्तिगत संस्करण 6.1.1 – Nelly

उत्तर

3

आपका कोड लिखा के रूप में तार्किक रूप से सही है और नतीजा यह है कि आप इसे करना चाहते हैं पैदा करता है:

CL-USER> (defun rev (l) 
      (cond 
      ((null l) '()) 
      (T (append (rev (cdr l)) (list (car l)))))) 
REV 
CL-USER> (rev '(1 2 3 4)) 
(4 3 2 1) 
CL-USER> (rev '()) 
NIL 
CL-USER> (rev '(1 2)) 
(2 1) 

यानी, प्रदर्शन के मामले में यह के साथ कुछ मुद्दों कर रहे हैं। फ़ंक्शन संलग्न करें, लेकिन इसकी अंतिम तर्क के अलावा सभी की एक प्रति उत्पन्न करती है। उदा।, जब आप ('(1 2)' (ए बी) '(3 4)) संलग्न करते हैं, तो आप एक चार नई विपक्षी कोशिकाएं बना रहे हैं, जिनकी कारें 1, 2, ए, और बी हैं। अंतिम एक का सीडीआर मौजूदा सूची है (3 4)।

(defun append (l1 l2) 
    (if (null l1) 
     l2 
     (cons (first l1) 
      (append (rest l1) 
        l2)))) 

वास्तव में कॉमन लिस्प के संलग्न नहीं है यही कारण है, क्योंकि आम लिस्प के संलग्न ले जा सकते हैं और अधिक से अधिक दो तर्क: क्योंकि के कार्यान्वयन संलग्न कुछ इस तरह होता है। यह दिखाने के लिए काफी करीब है कि अंतिम सूची के अलावा सभी को कॉपी क्यों किया गया है। अब, हालांकि क्या कि के अपने कार्यान्वयन के संदर्भ में इसका मतलब है पर देखने के फिरना:

(defun rev (l) 
    (cond 
    ((null l) '()) 
    (T (append (rev (cdr l)) (list (car l)))))) 

इसका मतलब यह है कि जब आप (1 2 3 4)की तरह एक सूची पीछे रहे हैं, यह है कि आप कर रहे हैं :

(append '(4 3 2) '(1))    ; as a result of (1) 
(append (append '(4 3) '(2)) '(1)) ; and so on...  (2) 

अब, लाइन (2) में, आप सूची कॉपी कर रहे हैं (4 3)। एक पंक्ति में, आप सूची (4 3 2) की प्रतिलिपि बना रहे हैं जिसमें एक प्रति (4 3) शामिल है। यही है, आप प्रतिलिपि कॉपी कर रहे हैं। यह स्मृति का एक बहुत अपर्याप्त उपयोग है।

एक और आम दृष्टिकोण एक संचयक चर और एक सहायक समारोह का उपयोग करता है। (ध्यान दें कि मैं ENDP, बाकी, पहले, और सूची * बजाय अशक्त, सीडीआर की, कार, और विपक्ष का उपयोग करें, क्योंकि यह यह स्पष्ट है कि हम कर रहे हैं कि बनाता है , सूचियों के साथ काम नहीं कर मनमाने ढंग से विपक्ष के पेड़ों। वे बहुत ज्यादा एक ही कर रहे हैं (लेकिन कुछ मतभेद हैं)।)

(defun rev-helper (list reversed) 
    "A helper function for reversing a list. Returns a new list 
containing the elements of LIST in reverse order, followed by the 
elements in REVERSED. (So, when REVERSED is the empty list, returns 
exactly a reversed copy of LIST.)" 
    (if (endp list) 
     reversed 
     (rev-helper (rest list) 
        (list* (first list) 
         reversed)))) 
CL-USER> (rev-helper '(1 2 3) '(4 5)) 
(3 2 1 4 5) 
CL-USER> (rev-helper '(1 2 3) '()) 
(3 2 1) 
इस सहायक समारोह के साथ

, यह राजस्व परिभाषित करने के लिए आसान है:

(defun rev (list) 
    "Returns a new list containing the elements of LIST in reverse 
order." 
    (rev-helper list '())) 
CL-USER> (rev '(1 2 3)) 
(3 2 1) 

कहा यही कारण है, बल्कि एक बाहरी सहायक समारोह की तुलना में, यह शायद अधिक लेबल का उपयोग करने के लिए आम हो जाएगा एक स्थानीय सहायक समारोह को परिभाषित करने के:

(defun rev (list) 
    (labels ((rev-helper (list reversed) 
      #| ... |#)) 
    (rev-helper list '()))) 

या , के बाद से कॉमन लिस्प पूंछ कॉल अनुकूलन करने के लिए गारंटी नहीं है, एक कर पाश अच्छे और साफ यहाँ भी है:

(defun rev (list) 
    (do ((list list (rest list)) 
     (reversed '() (list* (first list) reversed))) 
     ((endp list) reversed))) 
+0

बहुत बहुत धन्यवाद! आपके जवाब ने वास्तव में मेरी मदद की। – Nelly

+0

मुझे अभी भी एक प्रश्न है .. प्रारंभिक सूची में उप-सूचियां क्या हैं? मैंने "rev" में "mapcar" फ़ंक्शन का उपयोग करके थोड़ा सा कोड संशोधित करने का प्रयास किया, लेकिन मुझे परिणाम "शून्य" मिल गया ... क्या आप मुझे एक सुझाव दे सकते हैं? – Nelly

+0

@Nelly मुझे यकीन नहीं है कि आप क्या मतलब रखते हैं, और निश्चित रूप से यह अनुमान नहीं लगा सकता कि आप "मुझे परिणाम नील" प्राप्त करने में क्या समस्या है। आपको सूचियों के लिए किसी भी संशोधन की आवश्यकता नहीं है जिसमें तत्वों के रूप में सूचियां हैं। जब आप रिवर्स ((1 2) (3 4)) प्राप्त करते हैं ((3 4) (1 2)), एक ही तत्व के साथ एक नई सूची, लेकिन विपरीत क्रम में। –

1

एएनएसआई कॉमन लिस्प में, आप reverse समारोह का उपयोग करके सूची पलट सकता है (nondestructive: एक नई सूची आवंटित करती है), या nreverse (बिल्डिंग ब्लॉक या मौजूदा सूची की डेटा rearranges उलट एक निर्माण करने के लिए)।

> (reverse '(1 2 3)) 
(3 2 1) 

उद्धृत सूची अक्षर पर nreverse का उपयोग न करें; यह अपरिभाषित व्यवहार है और आश्चर्यजनक तरीकों से व्यवहार कर सकता है, क्योंकि यह de facto स्व-संशोधित कोड है।

0

यदि आप append जैसे मानक सीएल लाइब्रेरी फ़ंक्शंस का उपयोग कर सकते हैं, तो आपको reverse (Kaz suggested के रूप में) का उपयोग करना चाहिए।

अन्यथा, यदि यह एक व्यायाम (ज/डब्ल्यू या नहीं) है, तो आप इस कोशिश कर सकते हैं:

(defun rev (l) 
    (labels ((r (todo) 
      (if todo 
       (multiple-value-bind (res-head res-tail) (r (cdr todo)) 
        (if res-head 
         (setf (cdr res-tail) (list (car todo)) 
          res-tail (cdr res-tail)) 
         (setq res-head (list (car todo)) 
          res-tail res-head)) 
        (values res-head res-tail)) 
       (values nil nil)))) 
    (values (r l)))) 

पी एस। आपकी विशिष्ट त्रुटि समझ में नहीं आ रही है, कृपया अपने विक्रेता से संपर्क करें।

0

आप ढेर स्थान से बाहर होने की संभावना रन है; यह पूंछ की स्थिति के बाहर, एक रिकर्सिव फ़ंक्शन, rev पर कॉल करने का परिणाम है।

(defun reving (list result) 
    (cond ((consp list) (reving (cdr list) (cons (car list) result))) 
     ((null list) result) 
     (t (cons list result)))) 

आप rev समारोह तो हो जाता है::

(define rev (list) (reving list '())) 

उदाहरण:

* (reving '(1 2 3) '()) 
(3 2 1) 
* (reving '(1 2 . 3) '()) 
(3 2 1) 

* (reving '1 '()) 
(1) 
+0

क्षमा करें, मुझे समझ में नहीं आता कि "consp" का अर्थ क्या है .. क्या आप थोड़ा सा समझा सकते हैं? – Nelly

+0

'consp' प्रकार 'cons सेल' के लिए टाइप करें। प्रत्येक उचित सूची 'शून्य' में समाप्त होने वाली विपक्षी कोशिकाओं का एक अनुक्रम है। यदि आप '(विपक्ष 1 (विपक्षी 2)) का प्रयास करते हैं तो आपको' (1 2) 'की एक सूची मिल जाएगी। उपर्युक्त 'रीविंग' कोड में, यदि 'सूची' एक 'विपक्ष' है तो 'कार' को 'परिणाम' पर दबाएं और बाकी सूची ('cdr' के माध्यम से) पर पुन: कार्य करें। – GoZoner