2013-03-09 9 views
7

में मेमोरी उपयोग मैंने कुछ सामान्य उपकरण जैसे Heapy को मापने के लिए देखा है ताकि प्रत्येक ट्रैवर्सल तकनीक द्वारा कितनी मेमोरी का उपयोग किया जा सके लेकिन मुझे नहीं पता कि वे मुझे सही परिणाम दे रहे हैं या नहीं। संदर्भ देने के लिए यहां कुछ कोड दिया गया है।रिकर्सिव बनाम एक पुनरावर्तक ग्राफ ट्रैवर्सल

कोड आसानी से ग्राफ में अद्वितीय नोड्स की संख्या को मापता है। प्रदान की गई दो ट्रैवर्सल तकनीकें जैसे। count_bfs और count_dfs

import sys 
from guppy import hpy 
class Graph: 
    def __init__(self, key): 
     self.key = key  #unique id for a vertex 
     self.connections = [] 
     self.visited = False 

def count_bfs(start): 
    parents = [start] 
    children = [] 
    count = 0 
    while parents: 
     for ind in parents: 
      if not ind.visited: 
       count += 1 
       ind.visited = True 
       for child in ind.connections: 
         children.append(child) 

     parents = children 
     children = [] 
    return count 

def count_dfs(start): 
    if not start.visited: 
      start.visited = True 
    else: 
      return 0 

    n = 1 
    for connection in start.connections: 
     n += count_dfs(connection) 
    return n 


def construct(file, s=1): 
    """Constructs a Graph using the adjacency matrix given in the file 

    :param file: path to the file with the matrix 
    :param s: starting node key. Defaults to 1 

    :return start vertex of the graph 
    """ 
    d = {} 
    f = open(file,'rU') 
    size = int(f.readline()) 
    for x in xrange(1,size+1): 
     d[x] = Graph(x) 
    start = d[s] 
    for i in xrange(0,size): 
      l = map(lambda x: int(x), f.readline().split()) 
      node = l[0] 
      for child in l[1:]: 
       d[node].connections.append(d[child]) 
    return start 


if __name__ == "__main__": 
    s = construct(sys.argv[1]) 
    #h = hpy() 
    print(count_bfs(s)) 
    #print h.heap() 
    s = construct(sys.argv[1]) 
    #h = hpy() 
    print(count_dfs(s)) 
    #print h.heap() 

मैं क्या कारक कुल स्मृति उपयोग दो ट्रेवर्सल तकनीक अर्थात् में अलग है द्वारा जानना चाहते हैं। count_dfs और count_bfs? किसी के पास अंतर्ज्ञान हो सकता है कि dfs महंगा हो सकता है क्योंकि प्रत्येक फ़ंक्शन कॉल के लिए एक नया स्टैक बनाया गया है। प्रत्येक ट्रैवर्सल तकनीक में कुल मेमोरी आवंटन कैसे मापा जा सकता है?
क्या (टिप्पणी की गई) hpy कथन वांछित उपाय देते हैं?

कनेक्शन के साथ

नमूना फ़ाइल:

4 
1 2 3 
2 1 3 
3 4 
4 
+0

क्या आप चरम स्मृति उपयोग की तलाश में हैं? क्योंकि दोनों एल्गोरिदम के लिए, ग्राफ का उपयोग होने के कारण उपयोग की जाने वाली राशि ऊपर और नीचे जायेगी। जिसकी बड़ी चोटी ग्राफ के विवरण पर निर्भर हो सकती है। – Blckknght

+0

@Blckknght मैं कुल मेमोरी उपयोग की तलाश में हूं। एक संभावित एवेन्यू अलग-अलग ज्ञापन दिखाते हुए आंकड़ों का एक सेट हो सकता है। प्रत्येक ट्रैवर्सल तकनीक पर लागू 'एन' ग्राफ के लिए आवंटन। – ajmartin

उत्तर

3

यह एक अजगर सवाल है, यह अधिक महत्वपूर्ण हो सकता है कि स्टैक स्पेस कितनी मेमोरी है। Cpython की 1000 फ्रेम की कम सीमा है क्योंकि यह सी कॉल स्टैक के साथ अपने कॉल स्टैक को साझा करती है, जो बदले में ज्यादातर स्थानों में एक मेगाबाइट के आदेश तक ही सीमित है। इस कारण से आपको रिकर्सन गहराई को असंबद्ध होने पर लगभग हमेशा * पुनरावर्ती समाधानों को पुनरावृत्त करना चाहिए।

* पायथन के अन्य कार्यान्वयन में यह प्रतिबंध नहीं हो सकता है। Cpython और pypy के stackless रूपों में यह सटीक संपत्ति

1

यह मापने के लिए वास्तव में कितनी ज्यादा मेमोरी प्रयुक्त की जा रही है क्योंकि सिस्टम कैसे वे ढेर फ्रेम लागू में भिन्नता है कठिन है। आम तौर पर बोलते हुए, पुनरावर्ती एल्गोरिदम पुनरावृत्त एल्गोरिदम की तुलना में कहीं अधिक स्मृति का उपयोग करते हैं क्योंकि जब भी कोई नया फ़ंक्शन कॉल होता है तो प्रत्येक स्टैक फ्रेम को इसके चर के राज्य को संग्रहीत करना होगा। गतिशील प्रोग्रामिंग समाधान और पुनरावर्ती समाधानों के बीच अंतर पर विचार करें। रनटाइम एक रिकर्सिव की तुलना में एल्गोरिदम के पुनरावर्तक कार्यान्वयन पर बहुत तेज़ है।

यदि आपको वास्तव में पता होना चाहिए कि आपका कोड कितना मेमोरी उपयोग करता है, तो अपने सॉफ़्टवेयर को ओलिली डीबीजी (http://www.ollydbg.de/) जैसे डिबगर में लोड करें और बाइट्स को गिनें। हैप्पी कोडिंग!

1

आपकी विशिष्ट समस्या के लिए, मुझे नहीं पता कि कोई आसान समाधान होने वाला है या नहीं। ऐसा इसलिए है क्योंकि, ग्राफ़ ट्रैवर्सल का चरम स्मृति उपयोग ग्राफ़ के विवरण पर निर्भर करता है।

गहराई से पहले ट्रैवर्सल के लिए, सबसे बड़ा उपयोग तब आएगा जब एल्गोरिदम गहरी गहराई तक चलेगा। आपके उदाहरण ग्राफ में, यह 1->2->3->4 को पार करेगा, और प्रत्येक स्तर के लिए एक स्टैक फ्रेम बनाएं। तो जब यह 4 पर है, तो उसने सबसे अधिक स्मृति आवंटित की है।

चौड़ाई के पहले ट्रैवर्सल के लिए, उपयोग की गई स्मृति प्रत्येक गहराई पर नोड्स की संख्या और अगली गहराई में बाल नोड्स की संख्या के समान आनुपातिक होगी। वे मान सूचियों में संग्रहीत हैं, जो शायद ढेर फ्रेम से अधिक कुशल हैं। उदाहरण में, चूंकि पहला नोड सभी अन्य लोगों से जुड़ा हुआ है, यह तुरंत पहले चरण [1]->[2,3,4] के दौरान होता है।

मुझे यकीन है कि कुछ ग्राफ हैं जो एक खोज या दूसरे के साथ बेहतर प्रदर्शन करेंगे।

उदाहरण के लिए, एक लिंक की कल्पना करें जो एक लिंक्ड सूची की तरह दिखता है, एक ही लंबी श्रृंखला में सभी शीर्षकों के साथ। गहराई से पहले ट्रैवर्सल में बहुत ही उच्च चोटी मेमोरी उपयोग होगा, क्योंकि यह श्रृंखला के नीचे सभी तरह की मरम्मत करेगा, प्रत्येक स्तर के लिए एक स्टैक फ्रेम आवंटित करेगा। चौड़ाई-पहला ट्रैवर्सल बहुत कम स्मृति का उपयोग करेगा, क्योंकि प्रत्येक चरण पर ट्रैक रखने के लिए केवल एक ही बच्चे के साथ एक ही कशेरुका होगी।

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

आपके वर्तमान प्रोफाइलिंग कोड को आपके द्वारा इच्छित शीर्ष मेमोरी उपयोग नहीं मिलेगा, क्योंकि जब आप heap पर कॉल करते हैं तो उसे केवल ढेर पर ऑब्जेक्ट्स द्वारा उपयोग की जाने वाली मेमोरी मिलती है। यह आपके ट्रैवर्सल के पहले और बाद में समान होने की संभावना है। इसके बजाए, आपको ट्रैवलल फ़ंक्शंस में प्रोफाइलिंग कोड डालना होगा। मैं guppy के पहले से बने पैकेज इसे अपने आप को प्रयास करने के लिए नहीं मिल रहा है, लेकिन मुझे लगता है कि इस अपरीक्षित कोड काम करेगा:

from guppy import hpy 

def count_bfs(start): 
    hp = hpy() 
    base_mem = hpy.heap().size 
    max_mem = 0 
    parents = [start] 
    children = [] 
    count = 0 
    while parents: 
     for ind in parents: 
      if not ind.visited: 
       count += 1 
       ind.visited = True 
       for child in ind.connections: 
         children.append(child) 
     mem = hpy.heap().size - base_mem 
     if mem > max_mem: 
      max_mem = mem 
     parents = children 
     children = [] 
    return count, max_mem 

def count_dfs(start, hp=hpy(), base_mem=None): 
    if base_mem is None: 
     base_mem = hp.heap().size 

    if not start.visited: 
      start.visited = True 
    else: 
      return 0, hp.heap().size - base_mem 

    n = 1 
    max_mem = 0 
    for connection in start.connections: 
     c, mem = count_dfs(connection, base_mem) 
     if mem > max_mem: 
      max_mem = mem 
     n += c 
    return n, max_mem 

दोनों ट्रेवर्सल कार्यों अब एक (count, max-memory-used) टपल लौट आते हैं। अंतर देखने के लिए आप विभिन्न ग्राफों पर उन्हें आज़मा सकते हैं।

0

दो में से, गहराई से पहले कम स्मृति का उपयोग करता है यदि अधिकांश ट्रैवर्सल अधिकांश ग्राफ को मारते हैं।

लक्ष्य बेहतर हो सकता है जब लक्ष्य प्रारंभिक नोड के नजदीक होता है, या जब नोड्स की संख्या बहुत तेज़ी से नहीं जाती है तो आपके कोड में माता-पिता/बच्चे के सरणी छोटे रहते हैं (उदाहरण के लिए एक और उत्तर लिंक की गई सूची डीएफएस के लिए सबसे खराब मामला)।

ग्राफ आप खोज रहे हैं स्थानिक डेटा है, या क्या एक के रूप में जाना जाता है है "स्वीकार्य अनुमानी," एक * एक और एल्गोरिथ्म है कि बहुत अच्छा है: http://en.wikipedia.org/wiki/A_star

हालांकि, समय से पहले अनुकूलन सब बुराई की जड़ है । उस वास्तविक डेटा को देखें जिसे आप उपयोग करना चाहते हैं; यदि यह उचित मात्रा में स्मृति में फिट बैठता है, और खोज उचित समय में चलता है, इससे कोई फर्क नहीं पड़ता कि आप किस एल्गोरिदम का उपयोग करते हैं। एनबी, "उचित" क्या है जिसका उपयोग आप उस एप्लिकेशन पर निर्भर करते हैं जिसके लिए आप इसका उपयोग कर रहे हैं और हार्डवेयर पर संसाधनों की मात्रा जो इसे चलाएगी।

0

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

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

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