लिंक की गई सूचियाँ नोड्स के अंदर नोड्स को संग्रहीत करने के बजाय पॉइंटर्स का उपयोग क्यों करती हैं


121

मैंने जावा में बड़े पैमाने पर लिंक से पहले काम किया है, लेकिन मैं C ++ में बहुत नया हूं। मैं इस नोड वर्ग का उपयोग कर रहा था जो मुझे एक परियोजना में ठीक दिया गया था

class Node
{
  public:
   Node(int data);

   int m_data;
   Node *m_next;
};

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

Node *m_next;

इसके बजाय सूची में अगले नोड को इंगित करें

Node m_next;

मैं समझता हूं कि सूचक संस्करण का उपयोग करना बेहतर है; मैं तथ्यों पर बहस नहीं करने जा रहा हूं, लेकिन मुझे नहीं पता कि यह बेहतर क्यों है। मुझे इस बारे में स्पष्ट जवाब नहीं मिला कि मेमोरी मेमोरी के लिए पॉइंटर कैसे बेहतर है, और मैं सोच रहा था कि क्या यहां कोई मुझे बेहतर समझने में मदद कर सकता है।


14
@ खुद मुझे क्षमा करें? ऐसी भाषा क्यों नहीं होगी जहाँ कोई भी चीज़ एक पॉइंटर है जिसकी कोई लिंक नहीं है?
Angew अब

41
यह ध्यान रखना महत्वपूर्ण है कि ऑब्जेक्ट पॉइंटर्स बनाम संदर्भों के संदर्भ में सी और सी ++ जावा से कैसे भिन्न हैं। Node m_nextएक नोड का संदर्भ नहीं है, यह पूरे के लिए भंडारण Nodeहै।
ब्रायन कैन

41
@ स्‍वयं जावा में ऐसे प्‍वाइंटर्स होते हैं, जिनका आप केवल स्‍पष्‍ट रूप से उपयोग नहीं करते हैं।
m0meni

27
कछुए सभी तरह नीचे है नहीं एक विकल्प। पागलपन कहीं खत्म होना है।
व्हाट्सक्रैग

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

जवाबों:


218

यह सिर्फ बेहतर नहीं है, यह एकमात्र संभव तरीका है।

यदि आपने अपने अंदर कोई Node वस्तु संग्रहीत की है, तो क्या होगा sizeof(Node)? यह होगा sizeof(int) + sizeof(Node), जो कि बराबर sizeof(int) + (sizeof(int) + sizeof(Node))होगा, जो sizeof(int) + (sizeof(int) + (sizeof(int) + sizeof(Node)))अनंत के बराबर होगा , आदि।

ऐसा कोई ऑब्जेक्ट मौजूद नहीं हो सकता। यह असंभव है


25
* जब तक यह आलसी का मूल्यांकन नहीं किया जाता है। अनंत सूचियाँ संभव हैं, न कि केवल सख्त मूल्यांकन के साथ।
कैरिजिनेट 20

55
@Carcigenicate यह नोड ऑब्जेक्ट पर कुछ फ़ंक्शन का मूल्यांकन / निष्पादित करने के बारे में नहीं है - यह नोड के हर उदाहरण की मेमोरी लेआउट के बारे में है, जिसे किसी भी मूल्यांकन के होने से पहले, संकलन समय पर निर्धारित किया जाना चाहिए।
पीटरिस

6
@ दाविद यह ऐसा करने के लिए तार्किक रूप से असंभव है। आप की जरूरत है एक सूचक (अच्छी तरह से वास्तव में एक अविवेक) यहाँ - सुनिश्चित करें कि भाषा से आप इसे छुपा सकते हैं, लेकिन अंत में, कि चारों ओर कोई रास्ता नहीं।
वू

2
@ डेविड मैं भ्रमित हूँ। पहले आप इस बात से सहमत हैं कि यह तार्किक रूप से असंभव है, लेकिन फिर आप इस पर विचार करना चाहते हैं? C या C ++ में से कुछ भी निकालें - यह किसी भी भाषा में असंभव है जिसे आप कभी भी सपने देख सकते हैं जहां तक ​​मैं देख सकता हूं। यह संरचना एक अनंत पुनरावृत्ति की परिभाषा के द्वारा है और अप्रत्यक्ष स्तर के कुछ स्तर के बिना हम इसे नहीं तोड़ सकते।
वू

13
@बेनजामिन ने वास्तव में मुझे बताया (क्योंकि मुझे पता था कि कोई और इसे ऊपर ले जाएगा - अच्छी तरह से मदद नहीं की) कि हास्केल ने निर्माण समय पर थक्के आवंटित किए और इसलिए यह काम करता है क्योंकि वे थ्रक्स हमें वह अप्रत्यक्ष रूप से प्रदान करते हैं जिनकी हमें आवश्यकता है। यह भेस में अतिरिक्त डेटा के साथ एक संकेतक के अलावा कुछ भी नहीं है ...
Voo

178

जावा में

Node m_node

एक पॉइंटर को दूसरे नोड में स्टोर करता है। आपके पास इसके बारे में कोई विकल्प नहीं है। C ++ में

Node *m_node

एक ही बात का मतलब है। अंतर यह है कि सी ++ में आप वास्तव में ऑब्जेक्ट को एक पॉइंटर के विपरीत स्टोर कर सकते हैं। इसलिए आपको कहना होगा कि आपको एक पॉइंटर चाहिए। C ++ में:

Node m_node

इसका मतलब है कि नोड को यहां स्टोर करें (और यह स्पष्ट रूप से एक सूची के लिए काम नहीं कर सकता है - आप एक पुनरावर्ती रूप से परिभाषित संरचना के साथ समाप्त होते हैं)।


2
@ सलामन मुझे पहले से ही यह पता था। मैं सिर्फ यह जानना चाहता था कि यह एक पॉइंटर के बिना काम क्यों नहीं करेगा जो कि स्वीकार किए गए उत्तर को बहुत बेहतर समझा।
m0meni

3
@ AR7 वे दोनों एक ही तरह के स्पष्टीकरण दे रहे हैं, बस दो अलग-अलग तरीकों से। यदि आपने इसे "नियमित" चर के रूप में घोषित किया है, तो पहली बार एक निर्माता को बुलाया गया था, यह एक नए उदाहरण के लिए त्वरित होगा। लेकिन इससे पहले कि वह इसे तुरंत समाप्त कर दे - पहले वाले का कंस्ट्रक्टर समाप्त होने से पहले - सदस्य Nodeके स्वयं के कंस्ट्रक्टर को बुलाया जाएगा, जो एक और नए उदाहरण को त्वरित करेगा ... और आपको अंतहीन छद्म पुनरावृत्ति मिलेगा। यह वास्तव में पूरी तरह से सख्त और शाब्दिक शब्दों में इतना बड़ा आकार नहीं है , क्योंकि यह एक प्रदर्शन मुद्दा है।
Panzercrisis

लेकिन आप वास्तव में चाहते हैं कि सूची में किसी के अगले को इंगित करने का एक तरीका है, न Nodeकि यह वास्तव में पहले के अंदर है Node। तो आप एक पॉइंटर बनाते हैं, जो मूल रूप से जावा की वस्तुओं को संभालता है, जैसा कि आदिम के विपरीत है। जब आप किसी विधि को कॉल करते हैं या एक चर बनाते हैं, तो जावा ऑब्जेक्ट की एक प्रति या यहां तक ​​कि ऑब्जेक्ट को ही स्टोर नहीं करता है; यह एक ऑब्जेक्ट के संदर्भ को संग्रहीत करता है, जो अनिवार्य रूप से एक संकेतक है जिसके चारों ओर लिपटे एक छोटे से दस्ताने हैं। यह दोनों उत्तर अनिवार्य रूप से कह रहे हैं।
Panzercrisis

इसका आकार या गति मुद्दा नहीं है - इसका अभेद्य मुद्दा है। शामिल नोड ऑब्जेक्ट में एक नोड ऑब्जेक्ट शामिल होगा जिसमें एक नोड ऑब्जेक्ट शामिल होगा ... वास्तव में इसे संकलित करना असंभव है
pm100

3
@Panzercrisis मुझे पता है कि वे दोनों एक ही स्पष्टीकरण दे रहे हैं। यह दृष्टिकोण, हालांकि, मेरे लिए उतना उपयोगी नहीं था क्योंकि यह इस बात पर केंद्रित था कि मुझे पहले से क्या समझ थी: सी ++ में पॉइंटर्स कैसे काम करते हैं और जावा में पॉइंटर्स कैसे संभाले जाते हैं। स्वीकार किए गए उत्तर को विशेष रूप से संबोधित किया गया कि क्यों न सूचक का उपयोग करना असंभव होगा क्योंकि आकार की गणना नहीं की जा सकती है। दूसरी ओर, इस व्यक्ति ने इसे "एक पुनरावर्ती रूप से परिभाषित संरचना" के रूप में अधिक अस्पष्ट रूप से छोड़ दिया। पीएस अपनी व्याख्या जो आपने अभी लिखी है, उसे दोनों से बेहतर बताते हैं: डी।
m0meni

38

C ++ जावा नहीं है। जब आप लिखते हैं

Node m_next;

जावा में, यह लेखन के समान है

Node* m_next;

C ++ में। जावा में, सूचक निहित है, सी ++ में यह स्पष्ट है। अगर आप लिखेंगे

Node m_next;

C ++ में, आप Nodeउस वस्तु के अंदर सही का एक उदाहरण देते हैं जिसे आप परिभाषित कर रहे हैं। यह हमेशा होता है और इसे छोड़ा नहीं जा सकता है, इसे आवंटित नहीं किया जा सकता है newऔर इसे हटाया नहीं जा सकता है। यह प्रभाव जावा में प्राप्त करना असंभव है, और यह उसी सिंटैक्स के साथ जावा जो करता है, उससे बिल्कुल अलग है।


1
जावा में कुछ समान पाने के लिए संभवतः "एक्सटेंड" होगा यदि सुपरनोड नोड को बढ़ाता है, तो सुपरनोड्स में नोड के सभी गुण शामिल हैं और सभी अतिरिक्त स्थान आरक्षित करने होंगे। तो जावा में आप "Node का विस्तार Node" नहीं कर सकते हैं
Falco

@ फाल्को ट्रू, इनहेरिटेंस बेस क्लासेस के इन-प्लेस समावेश का एक रूप है। हालाँकि, चूंकि Java एकाधिक वंशानुक्रम (C ++ के विपरीत) की अनुमति नहीं देता है, आप केवल विरासत के माध्यम से एकल अन्य preexisting वर्ग के उदाहरण में खींच सकते हैं। इसलिए मैं इन-प्लेस सदस्य समावेशन के विकल्प के रूप में विरासत के बारे में नहीं सोचूंगा।
विस्फ़ोटक - मोनिका

27

आप एक पॉइंटर का उपयोग करते हैं, अन्यथा आपका कोड:

class Node
{
   //etc
   Node m_next; //non-pointer
};

... संकलक नहीं होगा , क्योंकि संकलक आकार की गणना नहीं कर सकता है Node। ऐसा इसलिए है क्योंकि यह स्वयं पर निर्भर करता है - जिसका अर्थ है कि संकलक यह तय नहीं कर सकता है कि यह कितनी मेमोरी का उपभोग करेगा।


5
इससे भी बदतर, कोई मान्य आकार मौजूद नहीं है: यदि k == sizeof(Node)आपके पास और आपके प्रकार में डेटा है, तो उसे भी sizeof(Node) = k + sizeof(Data) = sizeof(Node) + sizeof(Data)और फिर धारण करना होगा sizeof(Node) > sizeof(Node)
बिटमास्क

4
@bitmask वास्तविक संख्या में कोई मान्य आकार मौजूद नहीं है । यदि आप ट्रांसफिनाइट्स की अनुमति देते हैं, तो aleph_0काम करता है। (बस अत्यधिक पांडित्य :-))
k_g

2
@k_g खैर, C / C ++ मानक बताता है कि वापसी का मान sizeofएक अहस्ताक्षरित अभिन्न प्रकार है, इसलिए ट्रांसफ़ैट या वास्तविक आकार की भी आशा है। (और भी अधिक पांडित्यपूर्ण हो रहा है !: p)
थॉमस

@ थोमस: एक बात यह भी हो सकती है कि नेचुरल नंबर भी हों। : (पी -pedantic शीर्ष पर जा रहे हैं)
bitmask

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

13

बाद वाले ( Node m_next) को नोड को शामिल करना होगा । यह इसे इंगित नहीं करेगा। और फिर तत्वों का कोई संबंध नहीं होगा।


3
इससे भी बदतर, यह एक वस्तु के लिए तार्किक रूप से असंभव होगा जिसमें एक ही प्रकार का कुछ शामिल हो।
माइक सेमोर

क्या अब भी तकनीकी रूप से लिंकिंग नहीं होगी क्योंकि यह एक नोड होगा जिसमें एक नोड और इतने पर एक नोड होगा?
m0meni

9
@ AR7: नहीं, कंटेंट का मतलब है कि यह वस्तुतः ऑब्जेक्ट के अंदर है, इससे जुड़ा हुआ नहीं है।
माइक सेमोर

9

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

नीचे, मैंने C ++ में आइटमों की सूची का प्रबंधन करने के तरीके पर चार बदलाव किए हैं।

  1. raw_pointer_demoआपके जैसे ही दृष्टिकोण का उपयोग करता है - कच्चे पॉइंटर्स के उपयोग के लिए आवश्यक मैनुअल मेमोरी प्रबंधन। यहाँ C ++ का उपयोग केवल वाक्यात्मक-चीनी के लिए है , और उपयोग किया जाने वाला दृष्टिकोण अन्यथा C भाषा के अनुकूल है।
  2. में shared_pointer_demoसूची प्रबंधन अभी भी मैन्युअल रूप से किया जाता है, लेकिन स्मृति प्रबंधन है स्वत: (कच्चे संकेत का उपयोग नहीं करता)। यह बहुत कुछ वैसा ही है जैसा आपने शायद जावा के साथ अनुभव किया है।
  3. std_list_demoमानक-पुस्तकालय listकंटेनर का उपयोग करता है । इससे पता चलता है कि यदि आप स्वयं को रोल करने के बजाय मौजूदा पुस्तकालयों पर भरोसा करते हैं तो चीजें कितनी आसान हो जाती हैं।
  4. std_vector_demoमानक-पुस्तकालय vectorकंटेनर का उपयोग करता है । यह सूची संग्रह को एक एकल सन्निहित स्मृति आवंटन में प्रबंधित करता है। दूसरे शब्दों में, अलग-अलग तत्वों के संकेत नहीं हैं। कुछ खास चरम मामलों के लिए, यह काफी अक्षम हो सकता है। हालांकि, विशिष्ट मामलों के लिए, यह C ++ में सूची प्रबंधन के लिए अनुशंसित सर्वोत्तम अभ्यास है

ध्यान दें: इन सभी में, केवल raw_pointer_demoवास्तव में आवश्यकता है कि "लीक" मेमोरी से बचने के लिए सूची को स्पष्ट रूप से नष्ट कर दिया जाए। अन्य तीन विधियाँ स्वचालित रूप से सूची और उसकी सामग्री को तब नष्ट कर देंगी जब कंटेनर कार्यक्षेत्र से बाहर हो जाएगा (फ़ंक्शन के समापन पर)। बिंदु जा रहा है: C ++ इस संबंध में बहुत "जावा-जैसा" होने में सक्षम है - लेकिन केवल तभी जब आप अपने निपटान में उच्च-स्तरीय टूल का उपयोग करके अपने प्रोग्राम को विकसित करना चुनते हैं।


/*BINFMTCXX: -Wall -Werror -std=c++11
*/

#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <vector>
#include <memory>
using std::cerr;

/** Brief   Create a list, show it, then destroy it */
void raw_pointer_demo()
{
    cerr << "\n" << "raw_pointer_demo()..." << "\n";

    struct Node
    {
        Node(int data, Node *next) : data(data), next(next) {}
        int data;
        Node *next;
    };

    Node * items = 0;
    items = new Node(1,items);
    items = new Node(7,items);
    items = new Node(3,items);
    items = new Node(9,items);

    for (Node *i = items; i != 0; i = i->next)
        cerr << (i==items?"":", ") << i->data;
    cerr << "\n";

    // Erase the entire list
    while (items) {
        Node *temp = items;
        items = items->next;
        delete temp;
    }
}

raw_pointer_demo()...
9, 3, 7, 1

/** Brief   Create a list, show it, then destroy it */
void shared_pointer_demo()
{
    cerr << "\n" << "shared_pointer_demo()..." << "\n";

    struct Node; // Forward declaration of 'Node' required for typedef
    typedef std::shared_ptr<Node> Node_reference;

    struct Node
    {
        Node(int data, std::shared_ptr<Node> next ) : data(data), next(next) {}
        int data;
        Node_reference next;
    };

    Node_reference items = 0;
    items.reset( new Node(1,items) );
    items.reset( new Node(7,items) );
    items.reset( new Node(3,items) );
    items.reset( new Node(9,items) );

    for (Node_reference i = items; i != 0; i = i->next)
        cerr << (i==items?"":", ") << i->data;
    cerr<<"\n";

    // Erase the entire list
    while (items)
        items = items->next;
}

shared_pointer_demo()...
9, 3, 7, 1

/** Brief   Show the contents of a standard container */
template< typename C >
void show(std::string const & msg, C const & container)
{
    cerr << msg;
    bool first = true;
    for ( int i : container )
        cerr << (first?" ":", ") << i, first = false;
    cerr<<"\n";
}

/** Brief  Create a list, manipulate it, then destroy it */
void std_list_demo()
{
    cerr << "\n" << "std_list_demo()..." << "\n";

    // Initial list of integers
    std::list<int> items = { 9, 3, 7, 1 };
    show( "A: ", items );

    // Insert '8' before '3'
    items.insert(std::find( items.begin(), items.end(), 3), 8);
    show("B: ", items);

    // Sort the list
    items.sort();
    show( "C: ", items);

    // Erase '7'
    items.erase(std::find(items.begin(), items.end(), 7));
    show("D: ", items);

    // Erase the entire list
    items.clear();
    show("E: ", items);
}

std_list_demo()...
A:  9, 3, 7, 1
B:  9, 8, 3, 7, 1
C:  1, 3, 7, 8, 9
D:  1, 3, 8, 9
E:

/** brief  Create a list, manipulate it, then destroy it */
void std_vector_demo()
{
    cerr << "\n" << "std_vector_demo()..." << "\n";

    // Initial list of integers
    std::vector<int> items = { 9, 3, 7, 1 };
    show( "A: ", items );

    // Insert '8' before '3'
    items.insert(std::find(items.begin(), items.end(), 3), 8);
    show( "B: ", items );

    // Sort the list
    sort(items.begin(), items.end());
    show("C: ", items);

    // Erase '7'
    items.erase( std::find( items.begin(), items.end(), 7 ) );
    show("D: ", items);

    // Erase the entire list
    items.clear();
    show("E: ", items);
}

std_vector_demo()...
A:  9, 3, 7, 1
B:  9, 8, 3, 7, 1
C:  1, 3, 7, 8, 9
D:  1, 3, 8, 9
E:

int main()
{
    raw_pointer_demo();
    shared_pointer_demo();
    std_list_demo();
    std_vector_demo();
}

Node_referenceघोषणा पतों ऊपर जावा और सी ++ के बीच सबसे दिलचस्प भाषा-स्तरीय अंतर में से एक। जावा में, एक प्रकार की वस्तु की घोषणा Nodeकरना अलग-अलग आवंटित वस्तु के संदर्भ का उपयोग करेगा। C ++ में, आपके पास संदर्भ (पॉइंटर) बनाम प्रत्यक्ष (स्टैक) आवंटन का विकल्प है - इसलिए आपको स्पष्ट रूप से अंतर को संभालना होगा। ज्यादातर मामलों में आप प्रत्यक्ष आवंटन का उपयोग करेंगे, हालांकि सूची तत्वों के लिए नहीं।
ब्रेंट बर्नबर्न

पता नहीं क्यों मैं भी एक std :: deque की संभावना की सिफारिश नहीं की ।
ब्रेंट बर्नबर्न

8

अवलोकन

C ++ में ऑब्जेक्ट्स को रेफरेंस और आवंटित करने के 2 तरीके हैं, जबकि जावा में केवल एक ही तरीका है।

यह समझाने के लिए, निम्नलिखित आरेख, दर्शाते हैं कि स्मृति में वस्तुओं को कैसे संग्रहीत किया जाता है।

1.1 C ++ बिना पॉइंटर्स के आइटम

class AddressClass
{
  public:
    int      Code;
    char[50] Street;
    char[10] Number;
    char[50] POBox;
    char[50] City;
    char[50] State;
    char[50] Country;
};

class CustomerClass
{
  public:
    int          Code;
    char[50]     FirstName;
    char[50]     LastName;
    // "Address" IS NOT A pointer !!!
    AddressClass Address;
};

int main(...)
{
   CustomerClass MyCustomer();
     MyCustomer.Code = 1;
     strcpy(MyCustomer.FirstName, "John");
     strcpy(MyCustomer.LastName, "Doe");
     MyCustomer.Address.Code = 2;
     strcpy(MyCustomer.Address.Street, "Blue River");
     strcpy(MyCustomer.Address.Number, "2231 A");

   return 0;
} // int main (...)

.......................................
..+---------------------------------+..
..|          AddressClass           |..
..+---------------------------------+..
..| [+] int:      Code              |..
..| [+] char[50]: Street            |..
..| [+] char[10]: Number            |..
..| [+] char[50]: POBox             |..
..| [+] char[50]: City              |..
..| [+] char[50]: State             |..
..| [+] char[50]: Country           |..
..+---------------------------------+..
.......................................
..+---------------------------------+..
..|          CustomerClass          |..
..+---------------------------------+..
..| [+] int:      Code              |..
..| [+] char[50]: FirstName         |..
..| [+] char[50]: LastName          |..
..+---------------------------------+..
..| [+] AddressClass: Address       |..
..| +-----------------------------+ |..
..| | [+] int:      Code          | |..
..| | [+] char[50]: Street        | |..
..| | [+] char[10]: Number        | |..
..| | [+] char[50]: POBox         | |..
..| | [+] char[50]: City          | |..
..| | [+] char[50]: State         | |..
..| | [+] char[50]: Country       | |..
..| +-----------------------------+ |..
..+---------------------------------+..
.......................................

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

1.2 C ++ पॉइंटर्स पॉइंटर्स का उपयोग कर

class AddressClass
{
  public:
    int      Code;
    char[50] Street;
    char[10] Number;
    char[50] POBox;
    char[50] City;
    char[50] State;
    char[50] Country;
};

class CustomerClass
{
  public:
    int           Code;
    char[50]      FirstName;
    char[50]      LastName;
    // "Address" IS A pointer !!!
    AddressClass* Address;
};

.......................................
..+-----------------------------+......
..|        AddressClass         +<--+..
..+-----------------------------+...|..
..| [+] int:      Code          |...|..
..| [+] char[50]: Street        |...|..
..| [+] char[10]: Number        |...|..
..| [+] char[50]: POBox         |...|..
..| [+] char[50]: City          |...|..
..| [+] char[50]: State         |...|..
..| [+] char[50]: Country       |...|..
..+-----------------------------+...|..
....................................|..
..+-----------------------------+...|..
..|         CustomerClass       |...|..
..+-----------------------------+...|..
..| [+] int:      Code          |...|..
..| [+] char[50]: FirstName     |...|..
..| [+] char[50]: LastName      |...|..
..| [+] AddressClass*: Address  +---+..
..+-----------------------------+......
.......................................

int main(...)
{
   CustomerClass* MyCustomer = new CustomerClass();
     MyCustomer->Code = 1;
     strcpy(MyCustomer->FirstName, "John");
     strcpy(MyCustomer->LastName, "Doe");

     AddressClass* MyCustomer->Address = new AddressClass();
     MyCustomer->Address->Code = 2;
     strcpy(MyCustomer->Address->Street, "Blue River");
     strcpy(MyCustomer->Address->Number, "2231 A");

     free MyCustomer->Address();
     free MyCustomer();

   return 0;
} // int main (...)

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

चेतावनी: जावा इस दूसरी तकनीक की तरह स्मृति में वस्तुओं को आवंटित करता है, लेकिन, वाक्यविन्यास पहले तरीके की तरह है, जो नए लोगों को "सी ++" के लिए भ्रमित कर सकता है।

कार्यान्वयन

तो आपकी सूची का उदाहरण निम्नलिखित उदाहरण के समान हो सकता है।

class Node
{
  public:
   Node(int data);

   int m_data;
   Node *m_next;
};

.......................................
..+-----------------------------+......
..|            Node             |......
..+-----------------------------+......
..| [+] int:           m_data   |......
..| [+] Node*:         m_next   +---+..
..+-----------------------------+...|..
....................................|..
..+-----------------------------+...|..
..|            Node             +<--+..
..+-----------------------------+......
..| [+] int:           m_data   |......
..| [+] Node*:         m_next   +---+..
..+-----------------------------+...|..
....................................|..
..+-----------------------------+...|..
..|            Node             +<--+..
..+-----------------------------+......
..| [+] int:           m_data   |......
..| [+] Node*:         m_next   +---+..
..+-----------------------------+...|..
....................................v..
...................................[X].
.......................................

सारांश

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

अपडेट करें:

इसके अलावा उल्लेख के लायक, जैसा कि @haccks ने अपनी पोस्ट में टिप्पणी की है।

कभी-कभी, संदर्भ या ऑब्जेक्ट पॉइंटर्स, नेस्टेड आइटम (उर्फ "यूएमएल रचना") को इंगित करते हैं।

और कभी-कभी, संदर्भ या ऑब्जेक्ट पॉइंटर्स, बाहरी वस्तुओं (उर्फ "यूएमएल एकत्रीकरण") को इंगित करता है।

लेकिन, एक ही वर्ग के नेस्टेड आइटम को "नो-पॉइंटर" तकनीक के साथ लागू नहीं किया जा सकता है।


7

एक साइड नोट पर, यदि किसी वर्ग या संरचना का पहला सदस्य अगला पॉइंटर है (तो कोई वर्चुअल फ़ंक्शंस या किसी अन्य वर्ग की कोई विशेषता जो अगले वर्ग या संरचना का पहला सदस्य नहीं है), तो आप एक "आधार" वर्ग या संरचना का उपयोग केवल अगले पॉइंटर के साथ कर सकते हैं, और ऐप्प जैसे बुनियादी लिंक्ड सूची संचालन के लिए सामान्य कोड का उपयोग कर सकते हैं, पहले डालें, सामने से पुनः प्राप्त करें ...। ऐसा इसलिए है क्योंकि C / C ++ गारंटी देता है कि वर्ग या संरचना के पहले सदस्य का पता वर्ग या संरचना के पते के समान है। बेस नोड वर्ग या संरचना में केवल एक अगला पॉइंटर होगा जो मूल लिंक्ड लिस्ट फ़ंक्शन द्वारा उपयोग किया जाएगा, फिर बेस नोड प्रकार और "व्युत्पन्न" नोड प्रकारों के बीच कनवर्ट करने के लिए टाइपकास्टिंग का उपयोग किया जाएगा। साइड नोट - C ++ में, यदि बेस नोड क्लास में केवल एक अगला पॉइंटर है,


6

लिंक्ड सूची में पॉइंटर्स का उपयोग करना बेहतर क्यों है?

कारण यह है कि जब आप Nodeऑब्जेक्ट बनाते हैं , तो कंपाइलर को उस ऑब्जेक्ट के लिए मेमोरी आवंटित करनी होती है और उसके लिए ऑब्जेक्ट के आकार की गणना की जाती है।
किसी भी प्रकार के पॉइंटर का आकार संकलक के लिए जाना जाता है और इसलिए स्वयं के संदर्भ के साथ ऑब्जेक्ट के आकार को इंगित किया जा सकता है।

यदि Node m_nodeइसके बजाय प्रयोग किया जाता है, तो संकलक के आकार के बारे में कोई पता नहीं है Nodeऔर यह गणना की एक अनंत पुनरावृत्ति में फंस जाएगा sizeof(Node)। हमेशा याद रखें: एक वर्ग अपने प्रकार का सदस्य नहीं रख सकता है


5

क्योंकि इसमें C ++ में है

int main (..)
{
    MyClass myObject;

    // or

    MyClass * myObjectPointer = new MyClass();

    ..
}

में इसके बराबर है जावा

public static void main (..)
{
    MyClass myObjectReference = new MyClass();
}

जहां वे दोनों MyClassडिफ़ॉल्ट कंस्ट्रक्टर के उपयोग की एक नई वस्तु बनाते हैं ।


0

लिंक की गई सूचियां नोड्स के अंदर नोड्स को संग्रहीत करने के बजाय पॉइंटर्स का उपयोग क्यों करती हैं?

बेशक एक तुच्छ जवाब है।

वे नहीं किया, तो लिंक एक सूचक द्वारा अगले करने के लिए एक नोड, वे नहीं किया जाएगा जुड़ा हुआ सूचियों

एक चीज के रूप में जुड़ी हुई सूचियों का अस्तित्व इसलिए है क्योंकि हम वस्तुओं को एक साथ श्रृंखला में सक्षम करना चाहते हैं। उदाहरण के लिए: हमारे पास पहले से ही एक वस्तु है। अब हम उदाहरण के लिए, उस वास्तविक वस्तु (एक प्रति नहीं) को एक कतार के अंत में रखना चाहते हैं। वह अंतिम तत्व से एक लिंक जोड़कर प्राप्त किया जाता है जो कतार में पहले से ही हम प्रवेश कर रहे हैं। मशीन शब्दों में, यह अगले तत्व के पते के साथ एक शब्द में भर रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.