एक द्विआधारी खोज वृक्ष के ऊपर एक इटरेटर को लागू करने

वोट
30

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

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

मेरा प्रश्न यह है - वहाँ निम्नलिखित गुणों के साथ एक द्विआधारी खोज वृक्ष के ऊपर एक इटरेटर डिजाइन करने के लिए एक तरीका है?

  1. तत्वों आरोही क्रम में दौरा कर रहे हैं (यानी एक inorder ट्रावर्सल)
  2. next()और hasNext()प्रश्नों हे (1) समय में चलाते हैं।
  3. स्मृति के उपयोग हे है (1)

यह आसान बनाने के लिए, यह ठीक है अगर आप को लगता है कि वृक्ष संरचना यात्रा (यानी कोई सम्मिलन, हटाए जाने, या रोटेशन) के दौरान आकार बदल रहा है नहीं है, लेकिन अगर वहाँ एक समाधान है कि वास्तव में इस संभाल सकता था यह बहुत अच्छा होगा।

03/01/2011 को 02:54
का स्रोत उपयोगकर्ता
अन्य भाषाओं में...                            


8 जवाब

वोट
1

ट्री ट्रेवर्सल , विकिपीडिया से:

सभी नमूना कार्यान्वयन कॉल स्टैक अंतरिक्ष पेड़ की ऊंचाई के अनुपात में की आवश्यकता होगी। एक खराब संतुलित ट्री में, यह काफी महत्वपूर्ण हो सकता है।

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

लेख में हे (1) राज्य है, जो आसानी से एक इटरेटर अनुकूलित किया जा सकता के साथ यात्रा के लिए कुछ स्यूडोकोड है।

03/01/2011 को 03:09
का स्रोत उपयोगकर्ता

वोट
30

सरल संभव इटरेटर भंडार पिछली बार देखा कुंजी, और उसके बाद अगले चरण पर, उस कुंजी के लिए कम से कम ऊपरी सीमा के लिए पेड़ खोज करता है। पुनरावृत्ति हे (लॉग एन) है। यह बहुत ही सरल होने का लाभ है। चाबियाँ छोटे हैं तो iterators भी छोटे हैं। निश्चित रूप से यह पेड़ के माध्यम से पुनरावृत्ति की एक अपेक्षाकृत धीमी गति से जिस तरह से किया जा रहा है का नुकसान है। यह भी गैर-अद्वितीय दृश्यों के लिए काम नहीं करेगा।

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

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

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

03/01/2011 को 03:25
का स्रोत उपयोगकर्ता

वोट
3

ठीक है, मैं जानता हूँ कि यह पुराना है, लेकिन मैं माइक्रोसॉफ्ट के साथ एक साक्षात्कार में यह कहा गया था एक समय पहले और मैं इस पर थोड़ा काम करने का फैसला किया। मैं इस परीक्षण किया है और यह बहुत अच्छी तरह से काम करता है।

template <typename E>
class BSTIterator
{  
  BSTNode<E> * m_curNode;
  std::stack<BSTNode<E>*> m_recurseIter;

public:
    BSTIterator( BSTNode<E> * binTree )
    {       
        BSTNode<E>* root = binTree;

        while(root != NULL)
        {
            m_recurseIter.push(root);
            root = root->GetLeft();
        }

        if(m_recurseIter.size() > 0)
        {
            m_curNode = m_recurseIter.top();
            m_recurseIter.pop();
        }
        else
            m_curNode = NULL;
    }

    BSTNode<E> & operator*() { return *m_curNode; }

    bool operator==(const BSTIterator<E>& other)
    {
        return m_curNode == other.m_curNode;
    }

    bool operator!=(const BSTIterator<E>& other)
    {
        return !(*this == other);
    }

    BSTIterator<E> & operator++() 
    { 
        if(m_curNode->GetRight())
        {
            m_recurseIter.push(m_curNode->GetRight());

            if(m_curNode->GetRight()->GetLeft())
                m_recurseIter.push(m_curNode->GetRight()->GetLeft());
        }

        if( m_recurseIter.size() == 0)
        {
            m_curNode = NULL;
            return *this;
        }       

        m_curNode = m_recurseIter.top();
        m_recurseIter.pop();

        return *this;       
    }

    BSTIterator<E> operator++ ( int )
    {
        BSTIterator<E> cpy = *this;     

        if(m_curNode->GetRight())
        {
            m_recurseIter.push(m_curNode->GetRight());

            if(m_curNode->GetRight()->GetLeft())
                m_recurseIter.push(m_curNode->GetRight()->GetLeft());
        }

        if( m_recurseIter.size() == 0)
        {
            m_curNode = NULL;
            return *this;
        }       

        m_curNode = m_recurseIter.top();
        m_recurseIter.pop();

        return cpy;
    }

};
20/10/2012 को 05:53
का स्रोत उपयोगकर्ता

वोट
15

TokenMacGuy उल्लेख किया है आप इटरेटर में संग्रहीत एक ढेर का उपयोग कर सकते हैं। यहाँ जावा में इस की एक त्वरित परीक्षण किया कार्यान्वयन है:

/**
 * An iterator that iterates through a tree using in-order tree traversal
 * allowing a sorted sequence.
 *
 */
public class Iterator {

    private Stack<Node> stack = new Stack<>();
    private Node current;

    private Iterator(Node argRoot) {
        current = argRoot;
    }

    public Node next() {
        while (current != null) {
            stack.push(current);
            current = current.left;
        }

        current = stack.pop();
        Node node = current;
        current = current.right;

        return node;
    }

    public boolean hasNext() {
        return (!stack.isEmpty() || current != null);
    }

    public static Iterator iterator(Node root) {
        return new Iterator(root);
    }
}

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

31/07/2013 को 00:21
का स्रोत उपयोगकर्ता

वोट
0

क्या एक गहराई पहले खोज तकनीक का उपयोग कर के बारे में। इटरेटर वस्तु सिर्फ पहले से ही दौरा किया नोड्स के ढेर होना आवश्यक है।

21/05/2014 को 22:02
का स्रोत उपयोगकर्ता

वोट
0

आप ढेर का उपयोग करते हैं, आप केवल प्राप्त "अतिरिक्त स्मृति के उपयोग हे (ज), ज पेड़ की ऊंचाई है।" आप की जरूरत यह वर्तमान नोड का कोई अधिकार नहीं बच्चा है, - सही उप पेड़ के मिनट लगता है: -: लेकिन, आप केवल हे (1) अतिरिक्त स्मृति उपयोग करना चाहते हैं, तो आप यहाँ रिकॉर्ड करने की आवश्यकता विश्लेषण कर रहे हैं वर्तमान नोड सही बच्चा है तो जड़ से यह देखने के लिए, और यह सबसे कम पूर्वज है, जो सबसे कम अगले नोड है अद्यतन करने के रखने के लिए

public class Solution {
           //@param root: The root of binary tree.

           TreeNode current;
           TreeNode root;
           TreeNode rightMost;
           public Solution(TreeNode root) {

               if(root==null) return;
                this.root = root;
                current = findMin(root);
                rightMost = findMax(root);
           }

           //@return: True if there has next node, or false
           public boolean hasNext() {

           if(current!=null && rightMost!=null && current.val<=rightMost.val)    return true; 
        else return false;
           }
           //O(1) memory.
           public TreeNode next() {
                //1. if current has right child: find min of right sub tree
                TreeNode tep = current;
                current = updateNext();
                return tep;
            }
            public TreeNode updateNext(){
                if(!hasNext()) return null;
                 if(current.right!=null) return findMin(current.right);
                //2. current has no right child
                //if cur < root , go left; otherwise, go right

                    int curVal = current.val;
                    TreeNode post = null;
                    TreeNode tepRoot = root;
                    while(tepRoot!=null){
                      if(curVal<tepRoot.val){
                          post = tepRoot;
                          tepRoot = tepRoot.left;
                      }else if(curVal>tepRoot.val){
                          tepRoot = tepRoot.right;
                      }else {
                          current = post;
                          break;
                      }
                    }
                    return post;

            }

           public TreeNode findMin(TreeNode node){
               while(node.left!=null){
                   node = node.left;
               }
               return node;
           }

            public TreeNode findMax(TreeNode node){
               while(node.right!=null){
                   node = node.right;
               }
               return node;
           }
       }
24/04/2015 को 23:41
का स्रोत उपयोगकर्ता

वोट
0

हे (1) अंतरिक्ष, जिसका अर्थ है हम हे (ज) ढेर का उपयोग नहीं होगा का उपयोग करें।

शुरू करने के लिए:

  1. hasNext ()? अगर पेड़ पूरी तरह से चल रहा है current.val <= endNode.val जाँच करने के लिए।

  2. पता लगाएं मिनट के माध्यम से बाएं सबसे: हम हमेशा सबसे बाईं ओर लगाने के लिए अगले न्यूनतम मूल्य के लिए देख सकते हैं।

  3. एक बार बाएं सबसे न्यूनतम है की जाँच की (इसे नाम current)। अगला मिनट 2 मामलों होगा: अगर current.right = अशक्त, हम अगले मिनट के रूप में, current.right के सबसे बाईं ओर बच्चे की तलाश में रख सकते हैं। या, हम माता-पिता के लिए पीछे की ओर देखने की जरूरत है। के वर्तमान माता पिता नोड खोजने के लिए द्विआधारी खोज वृक्ष का प्रयोग करें।

नोट : जब माता-पिता के लिए द्विआधारी खोज कर रही है, यकीन है कि यह संतुष्ट parent.left = वर्तमान बनाते हैं।

क्योंकि: अगर parent.right == वर्तमान, कि माता-पिता से पहले दौरा किया गया है। द्विआधारी खोज वृक्ष में, हम है कि parent.val <parent.right.val पता है। हम इस विशेष मामले को छोड़ करने की जरूरत है, क्योंकि यह पाश ifinite की ओर जाता है।

public class BSTIterator {
    public TreeNode root;
    public TreeNode current;
    public TreeNode endNode;
    //@param root: The root of binary tree.
    public BSTIterator(TreeNode root) {
        if (root == null) {
            return;
        }
        this.root = root;
        this.current = root;
        this.endNode = root;

        while (endNode != null && endNode.right != null) {
            endNode = endNode.right;
        }
        while (current != null && current.left != null) {
            current = current.left;
        }
    }

    //@return: True if there has next node, or false
    public boolean hasNext() {
        return current != null && current.val <= endNode.val;
    }

    //@return: return next node
    public TreeNode next() {
        TreeNode rst = current;
        //current node has right child
        if (current.right != null) {
            current = current.right;
            while (current.left != null) {
                current = current.left;
            }
        } else {//Current node does not have right child.
            current = findParent();
        }
        return rst;
    }

    //Find current's parent, where parent.left == current.
    public TreeNode findParent(){
        TreeNode node = root;
        TreeNode parent = null;
        int val = current.val;
        if (val == endNode.val) {
            return null;
        }
        while (node != null) {
            if (val < node.val) {
                parent = node;
                node = node.left;
            } else if (val > node.val) {
                node = node.right;
            } else {//node.val == current.val
                break;
            }
        }
        return parent;
    }
}
27/01/2016 को 16:42
का स्रोत उपयोगकर्ता

वोट
0

परिभाषा के अनुसार, यह अगले () और hasNext () (1) समय हे में चलाने के लिए संभव नहीं है। यदि आप एक BST में एक विशेष नोड पर देख रहे हैं, तो आप, पता नहीं ऊंचाई और अन्य नोड की संरचना रहे हैं इसलिए आप न सिर्फ सही अगले नोड के लिए "कूद" कर सकते हैं।

हालांकि, अंतरिक्ष जटिलता (1) (BST खुद के लिए स्मृति को छोड़ कर) हे को कम किया जा सकता है। यहाँ जिस तरह से मैं सी में ऐसा होता है:

struct node{
    int value;
    struct node *left, *right, *parent;
    int visited;
};

struct node* iter_next(struct node* node){
    struct node* rightResult = NULL;

    if(node==NULL)
        return NULL;

    while(node->left && !(node->left->visited))
        node = node->left;

    if(!(node->visited))
        return node;

    //move right
    rightResult = iter_next(node->right);

    if(rightResult)
        return rightResult;

    while(node && node->visited)
        node = node->parent;

    return node;
}

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

यहाँ परीक्षक समारोह है कि iter_next () कॉल करता है और मूल्य इस पेड़ के लिए हर बार प्रिंट है:

                  27
               /      \
              20      62
             /  \    /  \
            15  25  40  71
             \  /
             16 21

int main(){

    //right root subtree
    struct node node40 = {40, NULL, NULL, NULL, 0};
    struct node node71 = {71, NULL, NULL, NULL, 0};
    struct node node62 = {62, &node40, &node71, NULL, 0};

    //left root subtree
    struct node node16 = {16, NULL, NULL, NULL, 0};
    struct node node21 = {21, NULL, NULL, NULL, 0};
    struct node node15 = {15, NULL, &node16, NULL, 0};
    struct node node25 = {25, &node21, NULL, NULL, 0};
    struct node node20 = {20, &node15, &node25, NULL, 0};

    //root
    struct node node27 = {27, &node20, &node62, NULL, 0};

    //set parents
    node16.parent = &node15;
    node21.parent = &node25;
    node15.parent = &node20;
    node25.parent = &node20;
    node20.parent = &node27;
    node40.parent = &node62;
    node71.parent = &node62;
    node62.parent = &node27;

    struct node *iter_node = &node27;

    while((iter_node = iter_next(iter_node)) != NULL){
        printf("%d ", iter_node->value);
        iter_node->visited = 1;
    }
    printf("\n");
    return 1;
}

कौन सा क्रमबद्ध क्रम में मूल्यों प्रिंट होगा:

15 16 20 21 25 27 40 62 71 
13/02/2016 को 06:56
का स्रोत उपयोगकर्ता

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more