2010-08-02 16 views
10

मान लीजिए कि मैं एक गहराई पहले खोज का उपयोग पार करने के लिए एक पेड़ है, और इसे traversing के लिए मेरे एल्गोरिथ्म कुछ इस तरह दिखता है: कई भाषाओं में अबएक स्टैक का उपयोग करने के लिए एक रिकर्सिव फ़ंक्शन को कैसे परिवर्तित करें?

algorithm search(NODE): 
    doSomethingWith(NODE) 
    for each node CHILD connected to NODE: 
    search(CHILD) 

वहाँ उदाहरण है अगर के लिए प्रत्यावर्तन के लिए अधिकतम गहराई है, रिकर्सन की गहराई एक निश्चित सीमा से अधिक है, तो प्रक्रिया एक ढेर ओवरफ्लो के साथ दुर्घटनाग्रस्त हो जाएगी।

इस समारोह को रिकर्सन के बिना कैसे लागू किया जा सकता है, और इसके बजाय एक ढेर के साथ? कई मामलों में, बहुत सारे स्थानीय चर हैं; वे कहाँ से संग्रहीत किया जा सकता है?

+1

मुझे यह प्रश्न इस तथ्य के कारण अनजाने विनोद का एक छोटा सा तत्व प्राप्त करने के लिए मिलता है कि अधिकांश प्रोग्रामिंग भाषाएं (हालांकि सभी नहीं) इसके लिए आंतरिक रूप से एक स्टैक का उपयोग करती हैं। बेशक, यह भी तथ्य है कि अधिकांश भाषाओं के लिए, गहराई से पहली बार खोज के साथ रिकर्सन सीमा को हिट करने के लिए आपको एक बेहद असंतुलित पेड़ या बहुत बहुत बड़ा होना चाहिए, इस पर विचार करते हुए कि आपको इसकी गहराई की आवश्यकता होगी लगभग 1000 और सबसे अधिक कहते हैं, संतुलित द्विआधारी पेड़ों में 2^गहराई -1 के बराबर कई तत्व होते हैं, जिसका अर्थ है, उस पेड़ के लिए, आपको अतिप्रवाह से पहले 2^1000 - 1 तत्वों की आवश्यकता होगी। – JAB

+0

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

+1

वास्तव में मेरा पेड़ बहुत बड़ा है, हालांकि समान नोड्स की बड़ी संख्या। तो समान नोड्स हैश टेबल में कैश किए जाते हैं लेकिन पेड़ फिर भी बहुत बड़ा होता है। – Ran

उत्तर

15

आप इसे बदल इसलिए जैसे एक ढेर का उपयोग करें:

algorithm search(NODE): 
    createStack() 
    addNodeToStack(NODE) 

    while(stackHasElements) 
     NODE = popNodeFromStack() 
     doSomethingWith(NODE) 
     for each node CHILD connected to NODE: 
     addNodeToStack(CHILD) 

अपने दूसरे प्रश्न का सवाल है:

कई मामलों में, टी यहां बहुत सारे स्थानीय चर हैं; वे कहाँ से संग्रहीत किया जा सकता है?

इन्हें वास्तव में उसी स्थान पर रखा जा सकता है जैसा वे मूल रूप से थे। यदि चर "doSomethingWith" विधि के लिए स्थानीय हैं, तो बस उन्हें उसमें ले जाएं, और इसे एक अलग विधि में दोबारा दोहराएं। इस विधि को ट्रैवर्सल को संभालने की आवश्यकता नहीं है, केवल प्रसंस्करण, और इसके अपने स्थानीय चर भी इस तरह से हो सकते हैं जो केवल इसके दायरे में काम करता है।

+0

शायद यह स्पष्ट है, लेकिन यदि स्थानीय प्रसंस्करण चर के अलावा नोड के लिए स्थानीय स्थिति है, तो आप उन्हें केवल NODE की परिभाषा में जोड़ते हैं। –

1

अनिवार्य रूप से आप अपने खुद के ढेर के ऊपर नया: या प्रकार-सुरक्षा के लिए, node* in_process[] = new node*[1024]; और इस पर अपने मध्यवर्ती मूल्यों डाल: एक अलग ट्रेवर्सल लिए

node** current = &in_process[0]; 
node* root = getRoot(); 

recurse(root, &current) ;** 

void recurse(node* root, node** current) ; 
    *(*current)++ = root; add a node 
    for(child in root) { 
    recurse(child, current); 
    } 
    --*current; // decrement pointer, popping stack; 
} 
4

push(root) 
while not empty: 
    node = pop 
    doSomethingWith node 
    for each node CHILD connected to NODE: 
     push(CHILD) 

एक समान ट्रैवर्सल के लिए नोड्स को रिवर्स ऑर्डर में धक्का दें।

आप अपने ढेर बह रहे हैं, तो यह शायद मदद नहीं करेगा, जैसा कि आप अपने ढेर उड़ा देंगे बजाय

यदि आप एक nextChild कार्य हो आप सभी बच्चों को आगे बढ़ाने से बच सकते हैं

+0

आप आम तौर पर अपने ढेर से पहले अपना स्टैक रास्ता उड़ते हैं ... स्टेक मेमोरी आकार अक्सर काफी कम मात्रा (यानी: 1 एमबी) तक सीमित होता है। –

+0

हां, लेकिन यदि आप 1 एम स्टैक को उड़ाने के लिए पर्याप्त रिकर्सिंग कर रहे हैं, तो आप आसानी से आसानी से परिमाण के 3 ऑर्डर को दूर करने के लिए पर्याप्त रूप से कुछ गलत कर रहे हैं। – deinst

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