एक बाइनरी ट्री फ्री


13

तो इससे पहले कि आप कुछ बुनियादी कंप्यूटर विज्ञान अवधारणाओं को पढ़ें।

  1. एक द्विआधारी पेड़ एक गतिशील रूप से आवंटित संरचना है (आमतौर पर ऑर्डर किए गए भंडारण के लिए उपयोग किया जाता है)।
  2. इसकी प्रकृति के कारण बाइनरी पेड़ों का ट्रावेल आमतौर पर पुनरावर्ती होता है;
    ऐसा इसलिए होता है क्योंकि लूपिंग के दो रास्ते होने पर लीनियर ट्रैवर्सल (लूप के माध्यम से) स्वाभाविक नहीं है।
    • पुनरावर्ती: इसका अर्थ है एक फ़ंक्शन जो स्वयं को कॉल करता है।
  3. पुराने जमाने की भाषाओं में, स्मृति प्रबंधन के लिए मैनुअल मेमोरी प्रबंधन की आवश्यकता होती है।
    • मैनुअल: इसका मतलब है कि आपको इसे स्वयं करना होगा।
  4. जब आप मैनुअल मेमोरी प्रबंधन करते हैं तो आपको वास्तविक रूप से पेड़ के प्रत्येक सदस्य को मुक्त करने के लिए अंतर्निहित प्रणाली से पूछना होगा।
    • नि: शुल्क: स्मृति को वैश्विक पियो के लिए पुनर्प्राप्त करें ताकि इसे फिर से उपयोग किया जा सके और आप मेमोरी से बाहर न भागें।
    • Freeing: यह फंक्शन को कॉल करके free()और इसे उस पॉइंटर को पास करके किया जाता है जिसे आप रिकवर करना चाहते हैं।
    • सूचक: यह एक आभासी छड़ी की तरह है। अंत में स्मृति है। जब आप मेमोरी मांगते हैं तो आपको एक पॉइंटर (वर्चुअल स्टिक) दिया जाता है जिसमें मेमोरी होती है। जब आप कर रहे हैं आप सूचक (आभासी छड़ी) वापस दे।

पुनरावर्ती समाधान:

freeTree(Node* node)
{
    freeTree(node->left);  
    freeTree(node->right);
    free(node);
}

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

आखिरी सवाल पर:

एसओ समस्या केंद्रों को पुनरावर्ती संस्करण को एक रैखिक समाधान में परिवर्तित करने के लिए (ताकि आपको मेमोरी का उपयोग न करना पड़े)।

नोड प्रकार दें

typedef struct Node Node;
struct Node
{
    Node* left;
    Node* right;
};

इन नोड्स के एक पेड़ को मुक्त करने के लिए एक फ़ंक्शन लिखें।

प्रतिबंध:

  • पुनरावृत्ति का उपयोग नहीं कर सकते (अप्रत्यक्ष रूप से भी नहीं)
  • ट्रैकिंग के लिए किसी भी गतिशील स्थान को आवंटित नहीं किया जा सकता है।

  • नोट O (n) समाधान है

विजेता:

  1. सबसे अच्छी जटिलता।
  2. टाई तोड़ 1: पहले प्रस्तुत किया
  3. टाई ब्रेक 2: पात्रों की कम से कम राशि।

जवाबों:


7

O (n) के बहुत करीब लगता है:

यह पेड़ पर गहराई से चलता है, और ->leftमाता-पिता पर नज़र रखने के लिए ट्रैवर्स किए गए नोड्स के पॉइंटर का उपयोग करता है ।

struct Node * node = root;
struct Node * up = NULL;

while (node != NULL) {
    if (node->left != NULL) {
        struct Node * left = node->left;
        node->left = up;
        up = node;
        node = left;
    } else if (node->right != NULL) {
        struct Node * right = node->right;
        node->left = up;
        node->right = NULL;
        up = node;
        node = right;
    } else {
        if (up == NULL) {
            free(node);
            node = NULL;
        }
        while (up != NULL) {
            free(node);
            if (up->right != NULL) {
                node = up->right;
                up->right = NULL;
                break;
            } else {
                node = up;
                up = up->left;
            }
        }
    }
}

+1 एकमात्र उत्तर के लिए टिक जोड़ें। नीचे प्रस्तुत समाधान की तुलना में यह थोड़ा अधिक जटिल है लेकिन बहुत अच्छा है।
मार्टिन यॉर्क

4

C99, 94, O (n)

संपादित करें: हर किसी का उल्लेख करने के लिए लगता है struct Nodeबस के रूप में Nodeके रूप में अगर typedefयह एड, तो मैं भी था।

यह वास्तव में मेरा पहला सी गोल्फ है। बहुत सारे सेगफॉल्ट्स।

वैसे भी, इसके लिए C99 की आवश्यकता है क्योंकि यह लूप के पहले स्टेटमेंट के लिए एक डिक्लेरेशन का उपयोग करता है।

void f(Node*n){for(Node*q;n;n=q)(q=n->left)?n->left=q->right,q->right=n:(q=n->right,free(n));}

उपयोग भी नहीं #define!

यह एल्गोरिथ्म पेड़ को बदलकर काम करता है ताकि शीर्ष नोड के पास कोई बच्चा न हो, और फिर उसे हटाकर सही बच्चे पर चला जाए।

उदाहरण के लिए, यदि हम पेड़ से शुरू करते हैं

 1
/ \
2 3
 \
 4

एल्गोरिदम पॉइंटर्स को उत्परिवर्तित करेगा ताकि पेड़ होगा

2
 \
 1
/ \
4 3

अब हम सबसे ऊपरी नोड को आसानी से हटा सकते हैं।


मैंने टाइपडिफ का उपयोग नहीं किया क्योंकि मेरा C ++ में था (आप भाषाओं के बीच इन छोटे अंतरों को भूल जाते हैं)। मैंने प्रश्न को अपडेट किया है इसलिए यह C और C ++ में समान काम करता है।
मार्टिन यॉर्क

@LokiAstari मैं वास्तव में c ++ नहीं जानता, और मैंने अभी हाल ही में C सीखना शुरू किया है। लेकिन मुझे इस का जवाब देने के लिए पर्याप्त पता था :-)
गर्वित हेकेलर

1
मैं अभी के लिए एक +1 करने जा रहा हूं। लेकिन मैंने अभी भी काम नहीं किया है कि यह कैसे काम कर रहा है इसलिए मैं टर्की के बाद वापस आऊंगा। :-)
मार्टिन यॉर्क

@ लॉकीस्टारी मूल रूप से इस तथ्य का उपयोग करता है कि सी केवल अभिव्यक्ति का उपयोग करने के लिए भावों और कथनों को एक साथ
मिलाता है

1

C / C ++ / Objective-C 126 अक्षर (इसमें आवश्यक अनुगामी न्यूलाइन भी शामिल है)

#define b(t)(t->left||t->right)
void f(Node*r){while(r&&b(r)){Node**p=&r,*c=b(r);while(c)p=&c,c=b(c);free(*p);*p=0;}free(r);}

O (n) समय में नहीं चलता है। लेकिन ओपी को इसकी आवश्यकता नहीं है, इसलिए यहां मेरा ओ (एन 2 ) समाधान है।

एल्गोरिथ्म: जड़ से एक पत्ती तक नीचे चलो। छोड़ दीजिए। तब तक दोहराएं जब तक कोई पत्तियां न हों। रूट जारी करें।

Ungolfed:

void freeTree (Node * root) {
    while (root && (root->left || root->right)) {
        Node ** prev = &root;
        Node * curr = root->left || root->right;
        while (curr != 0) {
            prev = &curr;
            curr = curr->left || curr->right;
        }
        free(*prev);
        *prev = 0;
    }
    free(root);
}

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

@ लोकीअस्तारी: बग को नोटिस करने के लिए धन्यवाद। इसे अब ठीक किया जाना चाहिए (हालांकि मैंने कोड का परीक्षण नहीं किया है)।
थॉमस ईडिंग

1

c ++ 99 O (n)

यहाँ छोरों की बात एक सूची में शामिल होने के लिए बहुत अच्छी है लेकिन पदानुक्रम में ऊपर और नीचे नहीं जा रही है। user300 ने इसे प्रबंधित किया (मैं प्रभावित हूं) लेकिन कोड को पढ़ना मुश्किल है।

इसका समाधान पेड़ को एक सूची में बदलना है।
चाल यह करने के लिए एक ही समय में अपने नोड्स को हटाने है।

void freeNode(Node* t)
{
    if (t == NULL)
    {   return;
    }

    // Points at the bottom left node.
    // Any right nodes are added to the bottom left as we go down
    // this progressively flattens the tree into a list as we go.    
    Node* bottomLeft    = findBottomLeft(t);


    while(t != NULL)
    {
        // Technically we don't need the if (it works fine without)
        // But it makes the code easier to reason about with it here.
        if (t->right != NULL)
        {
            bottomLeft->left = t->right;
            bottomLeft = findBottomLeft(bottomLeft);
        }
        // Now just free the curent node
        Node*   old = t;
        t = t->left;
        free(old);
    }
}

Node* findBottomLeft(Node* t)
{
    while(t->left != NULL)
    {
        t = t->left;
    }
    return t;
}

गोल्फ संस्करण

void f(Node*t){Node*o,*l=t;for(;t;free(o)){for(;l->left;l=l->left);l->left=t->right;o=t;t=t->left;}}

गोल्फ का विस्तार

void f(Node* t)
{
        Node*o,*l    = t;

        for(;t;free(o))
        {
            for(;l->left;l = l->left);
            l->left = t->right;
            o = t;
            t = t->left;
        }
}

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