Végrehajtási bejáró egy bináris keresési fa

szavazat
30

Már kódoló egy csomó különböző bináris keresési fa megvalósítások közelmúltban (AVL, ferde, treap) és kíváncsi vagyok, ha van egy különösen „jó” módszer egy bejáró bejárására ezeket a struktúrákat. A megoldás, amit használni most az, hogy minden egyes csomóponthoz a BST boltban mutató a következő és az előző elem a fa, amely csökkenti iteráció standard kapcsolt lista iteráció. Azonban nem igazán vagyok elégedett a válasszal. Ez növeli a tér használata egyes csomópontok két pointert (előző és következő), és bizonyos értelemben ez csak csalás.

Tudok egy utat az épület egy bináris keresési fa bejáró, amely O (h) kiegészítő tárhely (ahol h a fa magasságát) segítségével egy köteg nyomon követni a határ csomópontok, hogy vizsgálja meg később, de én ve ellenállt kódolás ezt fel, mert a memória használat. Reméltem van valami módja annak, hogy építsenek egy bejáró, amely csak állandó helyet.

A kérdésem a következő - van úgy, hogy tervezzen egy bejáró felett bináris kereső fába, az alábbi tulajdonságokkal?

  1. Elemek látogatott növekvő sorrendben (azaz inorder bejárása)
  2. next()és hasNext()lekérdezések futnak O (1) idő.
  3. Memóriahasználata O (1)

Hogy könnyebb, ez rendben van, ha feltételezzük, hogy a fa struktúra nem változik alakja alatt az iterációs (azaz nincs, -extenziók vagy forgatások), de ez lenne igazán jó, ha van egy megoldás, amely valóban képes kezelni ezt.

A kérdést 03/01/2011 02:54
a forrás felhasználó
Más nyelveken...                            


8 válasz

szavazat
1

Fa bejárás , a Wikipedia:

Minden mintát implementáció igényel hívás verem helyet arányos a fa magasságát. Egy rosszul kiegyensúlyozott fa, ez is elég jelentős.

Mi lehet eltávolítani a verem követelmény fenntartásával szülő mutatókat az egyes csomópontok, illetve a menet a fa. Abban az esetben, használata szálak, ez lehetővé teszi a nagymértékben javult inorder bejárása, bár visszakeresése a szülő csomópont szükséges előrendelésre és postorder bejárás lassabb lesz, mint egy egyszerű verem alapú algoritmus.

A cikk van némi pszeudokód iterációs O (1) állapotban, amely könnyen alkalmazkodik a bejáró.

Válaszolt 03/01/2011 03:09
a forrás felhasználó

szavazat
30

A lehető legegyszerűbb bejáró az utoljára látott gombot, majd a következő iteráció, megkeresi a fa, a legkevésbé felső határaként a kulcsot. Iteráció jelentése O (log n). Ennek az az előnye, hogy nagyon egyszerű. Ha a billentyűzeten kicsik, a bejárók is kicsi. Természetesen megvan az a hátránya, hogy viszonylag lassú módja iterációjával át a fát. Ugyancsak nem fog működni, nem egyedi szekvenciák.

Egyes fák használata pontosan végrehajtás már használja, mert ez fontos, az adott felhasználási, hogy a vizsgálat nagyon gyors. Ha a kulcsok száma az egyes csomópontok nagy, akkor a büntetést tárolására testvér mutatók nem túl megterhelő. A legtöbb B-fák használja ezt a módszert.

sok keresési fa megvalósítások tartani a szülő mutatót minden csomóponton egyszerűsítése egyéb műveletek. Ha van, hogy akkor egy egyszerű mutatót az utoljára látott csomópont, mint a bejáró állapotát. mindegyik ismétlésnél, akkor keresse meg a következő gyerek az utolsó látható csomópont szülő. ha nincs több testvére, akkor menj fel egy több szinten.

Ha ezek egyike sem technikák tetszik, akkor egy halom csomópontok tárolják a bejáró. Ez szolgálja a funkciója ugyanaz, mint a függvény hívási verem amikor ismételve a keresési fa, mint a normál, de ahelyett, átkötése testvérek és rekurzív a gyermekeket, akkor nyomja meg a gyerekek a verembe, és visszatér az egymást követő testvér.

Válaszolt 03/01/2011 03:25
a forrás felhasználó

szavazat
3

Ok, tudom, hogy ez a régi, de megkértek, ezt egy interjúban a Microsoft egy kicsit vissza, és úgy döntöttem, hogy dolgozni rajta egy kicsit. Kipróbáltam ezt, és ez meglehetősen jól működik.

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;
    }

};
Válaszolt 20/10/2012 05:53
a forrás felhasználó

szavazat
15

Ahogy említettük TokenMacGuy akkor egy halom tárolt bejáró. Itt egy gyors tesztelt végrehajtásának Java:

/**
 * 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);
    }
}

További változás lenne, hogy áthalad a fa építési idő, és mentse a bejárás egy listát. Használhatja a lista bejáró utána.

Válaszolt 31/07/2013 00:21
a forrás felhasználó

szavazat
0

Mi a helyzet egy mélységi keresés technika. A bejáró tárgy csak kell egy halom a már meglátogatott csomópontokat.

Válaszolt 21/05/2014 22:02
a forrás felhasználó

szavazat
0

Ha verem, csak elérni „Extra memória használat O (h), h az a magasság, a fa”. Azonban, ha azt szeretnénk, hogy csak O (1) extra memória, meg kell rögzíteni Íme elemzés: - Ha a jelenlegi csomópont jobb gyerek: megtalálni min jog al fa - Úgy aktuális csomópont nincs joga a gyermek, meg kell keresni azt a gyökér, és folyamatosan frissíti ez a legalacsonyabb őse, amely a legalacsonyabb következő csomópontot

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;
           }
       }
Válaszolt 24/04/2015 23:41
a forrás felhasználó

szavazat
0

Használata O (1) helyet, ami azt jelenti, nem fogjuk használni O (h) verem.

Kezdeni:

  1. hasNext ()? current.val <= endNode.val hogy ellenőrizze, ha a fa teljesen áthaladni.

  2. Keresse min keresztül legbaloldalibb: tudjuk alwasy keresni bal szélső találni a következő minimális értéket.

  3. Miután legbaloldalibb min van jelölve (nevezd meg current). Következő perc lesz 2 esetben: Ha current.right! = Null, tudjuk tartani keres current.right bal szélső gyermek, a jövő min. Vagy meg kell nézni hátra szülő. Használja bináris keresési fa, megtekintheti az aktuális szülő csomópont.

Megjegyzés : amikor egy bináris keresést szülő, győződjön meg arról, hogy megfelel parent.left = aktuális.

Mert: Ha parent.right == áram, ez a szülő must már járt korábban. A bináris keresési fa, tudjuk, hogy parent.val <parent.right.val. Meg kell hagyni ezt a különleges eset, mivel ez vezet a ifinite hurok.

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;
    }
}
Válaszolt 27/01/2016 16:42
a forrás felhasználó

szavazat
0

A meghatározás szerint, ez nem lehetséges, a következő () és hasNext () futtatni O (1) idő. Ha ránézünk egy adott csomópont egy BST, akkor fogalma sincs, magassága és szerkezete a többi csomópont, tehát akkor nem csak „ugrás” a helyes következő csomópontot.

Azonban, a tér bonyolultsága csökkenthető a O (1) (kivéve a memória a BST is). Itt van, ahogy én megtenném a C:

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;
}

A trükk az, hogy mindkét szülő kapcsolat, és a látogatott zászló minden egyes csomóponthoz. Véleményem érvelhetünk, hogy ez nem több helyet használat, egyszerűen része a node szerkezet. És természetesen, iter_next () kell hívni nélkül az állam a fa struktúra változó (természetesen), de azt is, hogy a „fogadó” zászlók nem változik értékeket.

Itt látható a tesztelő funkció, amely felhívja iter_next (), és kinyomtatja az értéket minden alkalommal ezt a fát:

                  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;
}

Melyik kiírja az értékeket rendezett sorrendben:

15 16 20 21 25 27 40 62 71 
Válaszolt 13/02/2016 06:56
a forrás felhasználó

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