2013-03-17 12 views
10

कई प्रणालियों में, head.reverse अंतरिक्ष सूची के आकार के अनुपात में होती है, जबकि last निरंतर स्थान की आवश्यकता होती आवश्यकता है।अंतरिक्ष जटिलता पिछले

वहाँ प्रणाली इस तरह के एक परिवर्तन प्रदर्शन करने के लिए कर रहे हैं? इसी प्रकार reverse.take n.reverse के लिए?

संपादित करें: मैं अपना प्रश्न विस्तारित करना चाहता हूं: मैं एक ठोस परिवर्तन के बाद नहीं हूं — मैं इस अंत तक अनुकूलन के बाद हूं।

+0

यकीन है कि क्या आप के बाद कर रहे हैं नहीं। एक पुनर्लेखन नियम यह कर सकता है, अगर वह आप जो चाहते हैं उसके करीब पर्याप्त है। –

+0

@DanielFischer: मैं नहीं बल्कि इस को हल करने के लिए एक सामान्य विधि में दिलचस्पी है। दूसरे उदाहरण के बारे में सोचो। – false

+0

यदि यह अभी भी आपकी रूचि रखता है, तो उत्तर इस बात पर निर्भर करता है कि सूची में कितने उपभोक्ता हैं; यदि 'अंतिम 'केवल एकमात्र है, तो इसे निरंतर स्थान और ओ (एन) समय में चलाना चाहिए; लेकिन अगर कुछ अन्य उपभोक्ता इस सूची का संदर्भ रखते हैं, तो यह आखिरी सेल में समाप्त होने पर 'आखिरी' बताए जाने पर अस्तित्व में आ जाएगा। इस प्रकार ओ (एन) अंतरिक्ष और समय। इसी तरह डैनियल वाग्नेर के जवाब में दिखाए गए 'टेकलास्ट' के लिए। - या हम सूचियों के * वास्तविक कार्यान्वयन * को बदल सकते हैं, स्पष्ट परिणामों के साथ कुंजी के रूप में उपयोग किए गए इंडेक्स के साथ स्वयं-संतुलित पेड़ के रूप में।क्लोजर उच्च शाखा कारक (32?) के साथ भी चतुर पेड़ का उपयोग करता है। –

उत्तर

1

आप इस के लिए एक सरल पुनर्लेखन नियम लिख सकते हैं।

http://www.haskell.org/haskellwiki/Playing_by_the_rules

फ्यूजन नियम यह भी पकड़ सकता है, निर्भर करता है कि रिवर्स एन्कोड किया गया है।

+0

आप 'head.reverse = last' घोषित करने का सुझाव देते हैं। सही? – false

1

हम ड्रॉप और पिछले

>>> last [1..10^5] 
100000 
(0.01 secs, 10496736 bytes) 
>>> last [1..10^6] 
1000000 
(0.05 secs, 81968856 bytes) 
>>> last [1..10^7] 
10000000 
(0.32 secs, 802137928 bytes) 


>>> drop (10^5-1) [1..10^5] 
[100000] 
(0.01 secs, 10483312 bytes) 
>>> drop (10^6-1) [1..10^6] 
[1000000] 
(0.05 secs, 82525384 bytes) 
>>> drop (10^7-1) [1..10^7] 
[10000000] 
(0.32 secs, 802142096 bytes) 

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


साइड नोट के रूप में मैंने अन्य कामकाज का परीक्षण किया है और नतीजा खराब है। खाली सूचियों शून्य हैं, और conses succ हैं:

takeLastN = foldl' (.) id . flip replicate tail 

lastN = foldl' (.) last . flip replicate init 
+1

लंबाई की गणना करने के लिए प्रभावी रूप से लंबाई के लिए आनुपातिक स्थान की आवश्यकता होगी, क्योंकि सूची केवल तब ही उपयोग की जा सकती है। सही? – false

+0

जब आप सूची की लंबाई की गणना करते हैं तो रिवर्स कारण के रूप में इतना नहीं है कि आपको परिणाम को जमा करने की आवश्यकता है (एक जोड़ें) इस प्रकार सभी प्रक्रियाओं के दौरान स्मृति का केवल एक "स्लॉट" आवश्यक है, विपरीत विपरीत जहां स्मृति की मात्रा है जब हम सूची को पार करते हैं तो हम अधिक से अधिक बढ़ रहे हैं, हम एक ही लंबाई की एक नई सूची बनाते हैं। – zurgl

+1

वैसे भी, जितना अधिक आप "सिस्टम" के बारे में बात करते हैं, मैंने सूची डेटा प्रकार के विशेष एन्कोडिंग के लिए कहीं कहीं पढ़ा है, हम निर्माण द्वारा सूची की लंबाई शामिल कर सकते हैं, फिर जब आप सूची की लंबाई मांगते हैं तो उत्तर है निरंतर समय और स्थान में वापसी। सूची में यह अतिरिक्त जानकारी है। लेकिन मुझे लगता है कि यह निर्भर प्रकार पर भरोसा करता है और मुझे यकीन नहीं है कि हम इसे हैकेल में कर सकते हैं, जैसा कि है। – zurgl

5

आप एक विशेष रूप से कुंठित आलसी प्राकृतिक संख्या के रूप में अपनी सूची का इलाज द्वारा reverse . take n . reverse बदल सकता है। सूचियों के रूप में एन्कोड आलसी प्राकृतिक की तुलना के लिए, घटाव drop है:

type LazyNat a = [a] 

lengthLazy :: [a] -> LazyNat a 
lengthLazy = id 

dropLazy :: LazyNat a -> [b] -> [b] 
dropLazy [] xs = xs 
dropLazy (_:n) (_:xs) = dropLazy n xs 
dropLazy _ _ = [] 

-- like Prelude.subtract, this is flip (-) 
subtractLazy :: Int -> LazyNat a -> LazyNat a 
subtractLazy = drop 

अब हम आसानी से "ले पिछले n" समारोह को लागू कर सकते हैं:

takeLast n xs = dropLazy (subtractLazy n (lengthLazy xs)) xs 

... और आप को पता है कि खुश हो जाएगा केवल n किसी भी समय पर विपक्ष को स्मृति में होना आवश्यक है। विशेष रूप से, takeLast 1 (या वास्तव में किसी भी takeLast N शाब्दिक N के लिए) लगातार स्मृति में चला सकते हैं। आप की तुलना क्या होता है जब आप क्या होता है जब आप GHCi में (reverse . take 5 . reverse) [1..] चलाने के साथ takeLast 5 [1..] चलाने कर इसकी पुष्टि कर सकते हैं।

बेशक

, मैं ऊपर बहुत विचारोत्तेजक नाम का उपयोग करने की कोशिश की है, लेकिन कोई वास्तविक कार्यान्वयन में आप सब बकवास ऊपर इनलाइन सकता है:

takeLast n xs = go xs (drop n xs) where 
    go lastn [] = lastn 
    go (_:xs) (_:n) = go xs n 
    go _  _  = [] 
संबंधित मुद्दे