मैं पुनरावर्तन का उपयोग किए बिना किसी पेड़ को कैसे पार कर सकता हूं?


19

मेरे पास मेमोरी नोड ट्री में बहुत बड़ा है और पेड़ को पीछे करने की आवश्यकता है। प्रत्येक बच्चे के लौटे हुए मानों को उनके मूल नोड में पास करना। यह तब तक किया जाना चाहिए जब तक कि सभी नोड्स के पास नोड नोड तक उनका डेटा बबल न हो।

ट्रैवर्सल इस तरह काम करता है।

private Data Execute(Node pNode)
{
    Data[] values = new Data[pNode.Children.Count];
    for(int i=0; i < pNode.Children.Count; i++)
    {
        values[i] = Execute(pNode.Children[i]);  // recursive
    }
    return pNode.Process(values);
}

public void Start(Node pRoot)
{
    Data result = Execute(pRoot);
}

यह ठीक काम करता है, लेकिन मुझे चिंता है कि कॉल स्टैक नोड पेड़ के आकार को सीमित करता है।

कोड को फिर से कैसे लिखा जा सकता है ताकि कोई पुनरावर्ती कॉल न Executeहो?


8
आपको या तो नोड्स पर नज़र रखने के लिए या पेड़ के आकार को बदलने के लिए अपने खुद के स्टैक को बनाए रखना होगा। देखें stackoverflow.com/q/5496464 और stackoverflow.com/q/4581576
रॉबर्ट हार्वे

1
मुझे इस Google खोज , विशेष रूप से मॉरिस ट्रैवर्सल पर बहुत मदद मिली ।
रॉबर्ट हार्वे

@ रोबर्टह्वे धन्यवाद रॉब, मुझे यकीन नहीं था कि यह किन शर्तों के तहत होगा।
रिएक्टगुलर

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

@KarlBielefeldt मानती है कि पेड़ हालांकि पूरी तरह से संतुलित है। कभी-कभी आपको ऐसे पेड़ों की मॉडलिंग करने की आवश्यकता होती है जो संतुलित नहीं होते हैं , और इस मामले में स्टैक को उड़ाना बहुत आसान है।
सेवाकाल

जवाबों:


27

यहाँ एक सामान्य उद्देश्य ट्री ट्रैवर्सल कार्यान्वयन है जो पुनरावृत्ति का उपयोग नहीं करता है:

public static IEnumerable<T> Traverse<T>(T item, Func<T, IEnumerable<T>> childSelector)
{
    var stack = new Stack<T>();
    stack.Push(item);
    while (stack.Any())
    {
        var next = stack.Pop();
        yield return next;
        foreach (var child in childSelector(next))
            stack.Push(child);
    }
}

आपके मामले में आप इसे इस तरह कह सकते हैं:

IEnumerable<Node> allNodes = Traverse(pRoot, node => node.Children);

एक श्वास के लिए पहले Queueका उपयोग करें Stack, पहले गहराई के बजाय, खोजें। PriorityQueueएक सर्वोत्तम पहली खोज के लिए उपयोग करें।


क्या मैं यह सोचने में सही हूं कि यह सिर्फ पेड़ को एक संग्रह में समतल कर देगा?
रिएक्टगुलर

1
@ मैथ्यू फोसकारिनी हां, यही इसका उद्देश्य है। बेशक, यह जरूरी नहीं कि वास्तविक संग्रह में ही हो। यह सिर्फ एक अनुक्रम है। आप डेटा को स्ट्रीम करने के लिए उस पर पुनरावृति कर सकते हैं, पूरे डेटा को मेमोरी में सेट करने की आवश्यकता के बिना।
सर्व

मुझे नहीं लगता कि इस समस्या का हल है।
रिएक्टगुलर

4
वह खोज की तरह स्वतंत्र संचालन करने वाले ग्राफ को ट्रेस नहीं कर रहा है, वह बच्चे के नोड्स से डेटा एकत्र कर रहा है। वृक्ष को समतल करने के लिए संरचना की जानकारी को नष्ट कर देता है जो उसे एकत्रीकरण करने के लिए चाहिए।
कार्ल बेज़ेलफेल्ट

1
FYI करें मुझे लगता है कि यह सही जवाब है जो इस सवाल की तलाश कर रहे ज्यादातर लोगों को लग रहा है। +1
एंडर्स अरपी

4

यदि आपके पास पहले से अपने पेड़ की गहराई के लिए एक अनुमान है, तो शायद यह आपके मामले के लिए स्टैक आकार को अनुकूलित करने के लिए पर्याप्त है? जब से आप एक नया सूत्र शुरू करते हैं, सी # 2.0 संस्करण में यह संभव है, यहां देखें:

http://www.atalasoft.com/cs/blogs/rickm/archive/2008/04/22/increasing-the-size-of-your-stack-net-memory-management-part-3.aspx

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


मैंने बस एक त्वरित परीक्षण किया। अपनी मशीन पर मैं स्टैकओवरफ़्लो तक पहुँचने से पहले 14000 पुनरावर्ती कॉल कर सकता था। यदि पेड़ संतुलित है तो 4 बिलियन नोड्स को स्टोर करने के लिए केवल 32 कॉल की आवश्यकता है। यदि प्रत्येक नोड 1 बाइट है (जो यह अभ्यस्त नहीं होगा) तो ऊंचाई के एक संतुलित पेड़ को स्टोर करने के लिए 4 जीबी रैम लगेगा। 32
एबेन स्कोव पेडर्सन

मुझे स्टैक में सभी 14000 कॉल का उपयोग करना था। पेड़ 2.6x10 ^ 4214 बाइट्स लेता है यदि प्रत्येक नोड एक बाइट है (जो यह अभ्यस्त नहीं होगा)
एसबेन स्कोव पेडर्सन

-3

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

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


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

2
यह विवाद यहाँ हर बार एक बार सामने आता है। कुछ पोस्टर आपके स्वयं के स्टैक को पुनरावृत्ति नहीं करने पर विचार करते हैं, जबकि अन्य बताते हैं कि वे सिर्फ एक ही बात स्पष्ट रूप से कर रहे हैं कि रनटाइम अन्यथा निहित होगा। इस तरह की परिभाषाओं के बारे में बहस करने का कोई मतलब नहीं है।
किलन फ़ॉथ

फिर आप रिकर्सन को कैसे परिभाषित करते हैं? मैं इसे एक ऐसे फंक्शन के रूप में परिभाषित करूंगा, जो अपनी परिभाषा में खुद को आमंत्रित करता है। आप निश्चित रूप से एक पेड़ को कभी भी ऐसा कर सकते हैं, जैसा कि मैंने अपने उत्तर में प्रदर्शित किया है।
सेवाकाल

2
क्या मैं इतने उच्च प्रतिनिधि स्कोर वाले किसी व्यक्ति पर क्लिक करने के कार्य का आनंद लेने के लिए बुरा हूं? यह इस वेबसाइट पर ऐसा दुर्लभ आनंद है।
रिएक्टगुलर

2
@ मट पर आओ, वह बच्चा सामान है। आप असहमत हो सकते हैं, जैसे कि अगर आप किसी पेड़ पर बम फेंकने से डरते हैं, जो बहुत गहरा है, तो यह एक उचित चिंता है। आप बस इतना कह सकते हैं।
माइक डनलैवी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.