2013-07-23 4 views
8

मेरे पास कई लंबी लिंक्ड सूचियां हैं (उनके पास 20,000 आइटम हैं)। उनके पास अलग-अलग शुरुआत होती है लेकिन अंततः वे कुछ नोड से उसी नोड को इंगित कर सकते हैं। मैंने इस तरह की लिंक्ड सूची को एक साथ बढ़ने और उनके बीच स्मृति साझा करने का फैसला किया है।साझा पॉइंटर्स रिकर्सिव डेटा संरचनाओं को दोबारा हटाते हैं और स्टैक ओवरफ्लो

है यही कारण है कि मैं साझा संकेत के साथ जुड़ा हुआ सूची लागू करने का फैसला किया है:

#include <memory> 
struct SharedLinkedList { 
    int someData; 
    std::shared_ptr<SharedLinkedList> next; 
}; 

इस तरह सब कुछ ठीक काम करता है। लिंक्ड सूचियों की अब आवश्यकता नहीं है। अगर वे अन्य लिंक सूची के साथ कुछ हिस्सा साझा करते हैं तो केवल उनके साझा किए गए हिस्से को हटा दिया जाता है।

समस्या वाले हिस्सों के बिना लंबी लिंक्ड सूचियों को हटाए जाने पर समस्याएं होती हैं। हटाना पहला तत्व के साथ शुरू होता है। यह अगले तत्व के संदर्भों की संख्या को कम करता है जिसे हटाया जा सकता है और यह स्टैक ओवरफ्लो तक रिकर्सिव रूप से दोहराता है।

यहां कोड का उदाहरण दिया गया है जो लंबी लिंक्ड सूची बनाता है और फिर इसे हटाने में विफल रहता है।

SharedLinkedList* beginningOfList; 
SharedLinkedList* actualElement = new SharedLinkedList(); 
SharedLinkedList* nextElement; 

beginningOfList = actualElement; 
for (int i = 0; i < 1000; i++) { // 100 is OK, 1000 is KO 
    nextElement = new SharedLinkedList(); 
    actualElement->next = std::shared_ptr<SharedLinkedList>(nextElement); 
    actualElement = nextElement; 
} 
delete beginningOfList; 

मैं निम्नलिखित में से किसी के लिए अग्रिम धन्यवाद:

  1. shared_pointers का स्पष्टीकरण और मैं क्या याद आ रही है की। मैं उनका उपयोग कैसे कर सकता हूं? और क्या यह भी उनका उपयोग कर किया जा सकता है? क्या स्मृति की इस तरह की साझाकरण उस चीज़ के लिए नहीं है जिसके लिए शेयर पॉइंटर्स का आविष्कार किया गया था?
  2. सलाह मेरे कोड
  3. इस कोड का उपयोग वैज्ञानिक कंप्यूटेशंस के लिए किया जाएगा जो मेरे कंप्यूटर पर चलाया जाएगा। क्या मैं ढेर के बड़े आकार के लिए किसी भी तरह से tweak कर सकते हैं?

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

संपादित करें:

बस भ्रम aviod करने के लिए: मैं दोहराने की है कि पूरे सूचियों साझा किया जा सकता चाहते हैं। तो कोई उन्हें पेड़ कह सकता है।

List1 शामिल हैं:: 1,2,3,4,5,6,7

यहाँ उदाहरण है।

List2 शामिल हैं: 6,6,6,1,2,3,4,5,6,7

सूची 3 में शामिल हैं: 10,11,12,1,2,3,4,5,6 , 7

मैं इसे 3 साझा लिंक्डलिस्ट में प्रस्तुत करना चाहता हूं जो कई बार 1,2,3,4,5,6,7 स्टोर करके मोमरी बर्बाद नहीं करता है लेकिन वे एक ही स्थान पर इंगित करते हैं। यही कारण है कि संदर्भ गिनती की आवश्यकता है।

delete list3; केवल उस हिस्से को हटाना है जो साझा नहीं किया गया है यानी तत्व 10,11,12।

+0

जहां तक ​​मैं समझता हूँ, तो समस्या आपके 'SharedLinkedList' का नाशक के कार्यान्वयन है: आप केवल अगले तत्व के लिए एक संदर्भ रखने के लिए इसके विनाश से बचने और मैन्युअल रूप से बाद में इसे नष्ट करने के लिए किया है। यह स्पष्ट रूप से पहले आइटम के विनाशक को बुलाता है, जो उसके बाद अगले आइटम के विनाशक को बुलाता है, और इसी तरह से। आपको आसानी से 'साझा लिंक्डलिस्ट' विनाशक के कार्यान्वयन को बदलने में सक्षम होना चाहिए, इसलिए यह रिकर्सिव फ़ंक्शन कॉल का उपयोग नहीं करता है (उदाहरण के लिए सूची के तत्वों पर 'while'-loop का उपयोग करना)। – jogojapan

+0

'std :: shared_ptr' के मानक 'std :: list' (या' std :: vector') का उपयोग क्यों न करें? –

+0

@jogojapan ऐसा लगता है कि 'SharedLinkList' कंपाइलर से उत्पन्न विनाशक का उपयोग करता है। और आप वास्तव में एक को जोड़ नहीं सकते जो शेष बचे हुए सूची में पुनरावृत्त हो; नोड्स को फिर से गिना जाने के लिए पूरा बिंदु है। – jamesdlin

उत्तर

8

आप shared_ptr का उपयोग करते हैं यह स्वामित्व का प्रबंधन करेगा तुम्हारे लिए। जब संदर्भ गणना 0 पर जाती है तो यह पॉइंट के विनाशक को बुलाएगी। अब ऑब्जेक्ट की ओर इशारा किया जाता है और इसके तत्व के रूप में अगला साझा पॉइंटर जो अगले को नष्ट कर देता है ...। इसका परिणाम स्मृति को हटाने का एक पुनरावर्ती तरीका है। अब आप स्मृति पुनरावृत्ति को रद्द करने का प्रयास कर सकते हैं।

void destroy(SharedLinkedList* l) { 
    auto next=l->next; // take 2nd element 
    delete l;   // delete first 

    while (next) 
    next=next->next; // move next forward, deleting old next 
    } 
+0

'हटाएं l;' साझा पॉइंटर को अंडरलेइंग में संदर्भ संख्या को अस्वीकार कर देगा और यह भी रिकर्सन शुरू करेगा। –

+0

@ जॉन बुम्पर नंबर, पहले अगली की एक प्रति बनाई गई है। तो दूसरे तत्व की संदर्भ संख्या (कम से कम) है 2. जब 'l' हटा दिया जाता है तो यह 1 है। विचार है कि पहले तत्व को खोने से पहले,' element_ptr' की प्रतिलिपि को दूसरी तत्व में बनाना है। इसलिए जब पहला तत्व हटा दिया जाता है तो दूसरा तत्व हटाया नहीं जाता है। –

+0

आप सही हैं। मुझे विश्वास नहीं है कि बहुत छोटा कोड असली काम है। लेकिन यह वास्तव में काम करता है। यह एक चमत्कार की तरह है। विशेष रूप से 'अगली = अगली-> अगली;' पहली नजर में कुछ अजीब लग सकता है, लेकिन यह कर सकता है। मुझे केवल समय बचाने के कारण साझा हिस्से के माध्यम से पुन: प्रयास करने के बारे में अतिरिक्त देखभाल करने की आवश्यकता नहीं थी। अपने कोड को विनाशक को स्थानांतरित करना भी मुश्किल था क्योंकि रेखा 'अगला = अगला-> अगला' भी विनाशक को कॉल करती है। लेकिन मैं इसे करने में कामयाब रहा और यह तेजी से काम करता है, निर्दोष रूप से और ढेर को उड़ नहीं देता है। आपकी जीनियलिटी और बहुत धन्यवाद के लिए बधाई। –

4

सामान्य तौर पर, shared_ptr शायद नहीं जुड़ा हुआ सूचियों के लिए एक अच्छा विचार है आप का कहना है कारण के लिए, है।इस मामले में, आप को शायद इसे हाथ से करना है, प्रत्येक नोड में अभिभावक गिनती को बनाए रखना है। (यह पाश जो shared_ptr साथ ढेर अतिप्रवाह से बचा जाता है किसी प्रकार का बाहर काम करने के शायद संभव है, लेकिन परिणाम शायद हाथ से स्मृति प्रबंध की तुलना में अधिक जटिल हो जाएगा।)

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