2011-01-05 9 views
5

मैं एमआईटी ओपन कोर्स वेयर quizes में से कुछ के माध्यम से पढ़ रहा है और वे एक सवाल है कि इस तरह से चला जाता है था:इन 2 कार्यों के बीच गति अंतर इतना बड़ा क्यों है?

6) दो कार्यों नीचे निर्दिष्ट है कि एक "लगता है कि एक नंबर खेल खेलने के लिए उपयोग किया जाता है पर विचार करें। "

def cmpGuess(guess): 
"""Assumes that guess is an integer in range(maxVal). returns -1 if guess is < than the magic number, 0 if it is equal to the magic number and 1 if it is greater than the magic number.""" 
def findNumber(maxVal): 
"""Assumes that maxVal is a positive integer. Returns a number, num, such that cmpGuess(num) == 0.""" 
Write a Python implementation of findNumber that guesses the magic number defined by cmpGuess. Your program should have the lowest time complexity possible. """ 

यहाँ मेरी कार्यान्वयन है:

def find(maxVal): 
    ceiling = maxVal 
    floor = 0 

    while 1: 
     med = ((ceiling + floor)/2) 
     res = cmp(med) 
     if res == 1: 
      ceiling = med 
     elif res == -1: 
      floor = med 
     else: 
      return med 

और यहाँ उत्तर पुस्तिका कार्यान्वयन जनसंपर्क है शिक्षक द्वारा ovided:

def findNumber(maxVal): 
    """ Assumes that maxVal is a positive integer. Returns a number, num, such that cmpGuess(num) == 0 """ 
    s = range(0, maxVal) 
    return bsearch(s, 0, len(s) -1) 

def bsearch(s, first, last): 
    if (last-first) < 2: 
     if cmp(s[first]) == 0: 
      return first 
    else: 
     return last 

    mid = first + (last -first)/2 
    if cmp(s[mid]) == 0: 
     return s[mid] 
    if cmp(s[mid]) == -1: 
     return bsearch(s, first, mid -1) 
    return bsearch(s, mid + 1, last) 

यह सीएमपी हमारे दोनों कार्यों द्वारा इस्तेमाल किया समारोह है, कल्पना के अनुसार:

def cmp(guess): 
    if guess > num: 
     return 1 
    elif guess < num: 
     return -1 
    else: return 0 

एक प्रमुख अंतर यह है कि मेरी समाधान पुनरावृत्ति है और शिक्षक की कि पुनरावर्ती है । मैंने अधिकतम कार्यों = 1000,000 के साथ हमारे दोनों कार्यों के 1000 रन का समय दिया। यहाँ समय का टुकड़ा है:

t = timeit.Timer('find(1000000)', 'from __main__ import find,cmp') 
t1 = timeit.Timer('findNumber(1000000)', 'from __main__ import findNumber,bsearch') 
print str(t.timeit(1000)) 
print str(t1.timeit(1000)) 

मेरे रन ले लिया: 0.000621605333677s चलाने शिक्षकों ले लिया: 29.627s
यह संभवतः सही नहीं हो सकता। मैंने लगातार कई बार समय दिया, और सभी मामलों में दूसरा समारोह हास्यास्पद 30 के परिणामों के साथ आया। मैंने एमआईटी द्वारा प्रदान किए गए दस्तावेज़ से सीधे समाधान फ़ंक्शन चिपकाया। कोई विचार?

+3

पहला प्रश्न (मुझे लगता है कि आपने पहले इसे चेक किया है, लेकिन आइए सुनिश्चित करें): क्या दोनों सही उत्तर देते हैं? जैसा कह रहा है: यदि इसे सही नहीं होना है, तो मैं इसे 0 के रूप में कम कर सकता हूं। – delnan

+0

's = रेंज (0, maxVal)' ??? शिक्षक के समाधान के लिए 'ओ (अधिकतम) 'स्पेस की आवश्यकता होती है। – Bolo

+0

हाँ, दोनों सही हैं, एक दूसरे के मुकाबले धीमी गति के आदेश हैं। – Steve

उत्तर

4

आपने कहा कि आपने यह सुनिश्चित करने के लिए दोनों स्क्रिप्ट का परीक्षण किया है कि वे एक ही जवाब देते हैं, लेकिन वे नहीं करते हैं। शिक्षक की लिपि, जैसा आपने लिखा है, हमेशा अंतिम तत्व लौटाएगा। यह इन पंक्तियों की वजह से है:

def bsearch(s, first, last): 
    if (last-first) < 2: 
     if cmp(s[first]) == 0: 
      return first 
    else: 
     return last 

def bsearch(s, first, last): 
    if (last-first) < 2: 
     if cmp(s[first]) == 0: 
      return first 
     else: 
      return last 

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

if cmp(s[mid]) == -1: 

को
if cmp(s[mid]) == 1: 

यह वास्तव में सुस्ती के प्रश्न का उत्तर नहीं था लाइन बदलकर तय के साथ एक गलती है (जैसा कि इंगित किया गया है) ओ (एन) मेमोरी के आवंटन के कारण (यह एक बड़ा है), रिकर्सन, लिस्ट लुक-अप, एक बार की बजाय प्रत्येक bsearch कॉल के लिए संभवतः दो बार सीएमपी को कॉल करना और परिणाम संग्रह करना, और (last - first) < 2 प्रत्येक कॉल के लिए bsearch पर स्पष्ट रूप से जांचें क्योंकि वह परिवर्तनीय last को शामिल करने के रूप में उपयोग कर रहा है संभावित मूल्यों की सीमा में डी यह उच्चतम संभव मूल्य से 1 अधिक होने के बजाय। वैसे, अपने खुद के कोड लाइन को बदलने के द्वारा एक बालक सा तेजी से बनाया जा सकता है:

  floor = med 

  floor = med + 1 

ताकि आप खोज सीमा से मेड को छोड़कर कर रहे हैं। आप पहले ही जानते हैं कि यह सीएमपी परिणाम के आधार पर मूल्य नहीं है। वैसे, मैं cmp का उपयोग अपने स्वयं के फ़ंक्शन नाम के रूप में नहीं करता क्योंकि यह एक पायथन अंतर्निहित फ़ंक्शन है (मुझे पता है कि यह spec में cmpGuess है)।

+0

बस सोच रहा था, क्या आपने वह कोर्स लिया था या आप Opencourseware सामान का भी पालन कर रहे हैं? – Steve

+0

नहीं, मैंने कोर्स नहीं लिया है या ओसीडब्ल्यू पर इसे देखा है, लेकिन मैंने कुछ अन्य लोगों को देखा है। मैंने पहली बार मूल समाधान को देखने का फैसला किया जब मैंने पहली त्रुटि (इंडेंटेशन) देखी। मैंने इन समस्याओं के बारे में ओसीडब्ल्यू को एक ईमेल भेजा ताकि उम्मीद है कि समाधान को सही किया जाएगा। –

0

मेरे पास इस समय पाइथन स्थापित नहीं है, इसलिए एक नज़र से शायद शिक्षक ने रिकर्सन (बसेर्च में) का उपयोग किया था?

+2

यह एक उल्लेखनीय मंदी या 'अधिकतम रिकर्सन गहराई से अधिक समझा जाएगा, लेकिन 47662x मंदी नहीं होगी। – delnan

+0

@ डेलनान: अधिकतम रिकर्सन गहराई math.log (1000000.0, 2.0) के बारे में है ... लगभग 20. –

7

सबसे स्पष्ट बात यह है कि मैं देख सकता हूं कि हर बार जब आप शिक्षक के कार्य को बुलाते हैं तो यह 1,000,000 पूर्णांक (पायथन 2.x मानते हुए) की एक सूची बनाता है, और फिर जब यह लौटाता है तो यह उस सूची को फिर से नष्ट कर देता है।

इसमें कुछ समय लग रहा है।

+1

आह, हाँ - वास्तव में कुछ समय लग सकता है। पूरी तरह से भूल गया कि 'रेंज' एक सूची बनाता है (पायथन 3 'रेंज' एक स्मार्ट इटरेटर बनाता है जो कि यहां तक ​​कि सस्ता भी प्रदान करता है, क्योंकि यह चालाक है और तर्कों से इंडेक्सिंग से एनएच आइटम की गणना करता है)। – delnan

+0

आप पाइथन के पुराने संस्करणों में आलसी उत्पन्न करने के लिए xrange का उपयोग कर सकते हैं। वास्तव में, xrange का उपयोग करने के लिए _not_ का कोई कारण नहीं है? – pisswillis

+0

@ पिसविल्लिस, हाँ लेकिन अक्सर नहीं। उदाहरण के लिए, आप xrange (या पायथन 3.x में 'श्रेणी') का टुकड़ा नहीं कर सकते हैं। – Duncan

3

मुझे एक जवाब के रूप में मेरी टिप्पणी दोहराएँ: range(maxval) पूरी सूची आबंटित करता है, तो शिक्षक एल्गोरिथ्म Θ(maxval) अंतरिक्ष जटिलता और इस तरह Θ(maxval) समय जटिलता (जैसे एक सूची बनाने में समय लगता है) है। इसलिए, शिक्षक का समाधान "सबसे कम समय जटिलता संभव है।"

जब xrange(maxval) का उपयोग किया जाता है, तो पूरी सूची अब आवंटित नहीं की जाती है। आपके और शिक्षक दोनों के समाधान में Θ(log(maxval)) समय जटिलता है।

इसके अलावा, आपके समाधान में Θ(1) अंतरिक्ष जटिलता है, जबकि (अनुकूलित) शिक्षक के समाधान में Θ(log(maxval)) अंतरिक्ष जटिलता है - रिकर्सिव कॉल स्टैक मेमोरी का उपभोग करती है।

3

शिक्षक के संस्करण के साथ तीन चीजें गलत हैं, जिनमें से सभी ओपी के संस्करण में तय की गई हैं।

  1. s = range(maxVal)() xrange का उपयोग अजगर 2 में एक सूची बनाता है समय सूची बनाने और इसे नष्ट करने के लिए बचाता है।हालांकि एस का उपयोग करने का पूरा विचार एक बकवास है, क्योंकि सभी प्रासंगिक I के लिए s[i] == i, इसलिए इसे अभी-अभी फेंक दिया जा सकता है, लुक-अप को बचाया जा सकता है।

  2. रिकर्सन: रिकर्सन गहराई math.log (1000000.0, 2.0) के बारे में है ... लगभग 20। तो खोज के लिए कॉल के बारे में 20 फ़ंक्शन कॉल नम्बर(), और फ़ंक्शन कॉल वापस कूदने की तुलना में बहुत महंगे हैं थोड़ी देर की लूप की शुरुआत के लिए।

  3. यह cmp(s[mid]) को प्रति बार एक बार प्रति अनुमान के मुकाबले दो बार कॉल करता है, तो यह एक और 20 बर्बाद फ़ंक्शन कॉल नम्बर() के प्रति कॉल पर कॉल करता है।

संबंधित मुद्दे