Binary Tree περιστροφή

ψήφοι
3

Δουλεύω για την εφαρμογή ενός AVL δέντρου αναζήτησης. Μέχρι στιγμής έχω τελειώσει το τμήμα κωδικοποίησης και έχω αρχίσει τις δοκιμές του για σφάλματα. Ανακάλυψα ότι οι μέθοδοι περιστροφής του κόμβου μου ζητούσαν και για όνομα του Θεού, δεν μπορώ να καταλάβω ποιο είναι το πρόβλημα.

Ο αλγόριθμος λειτουργεί όπως θα έπρεπε σε χαρτί, αλλά όταν εκτελείται σε ένα μηχάνημα καλά ... διαρροές κόμβους του δέντρου.

Αυτή είναι η μέθοδος που χρησιμοποιείται για να περιστρέφει ένα κόμβο προς τα αριστερά: http://pastebin.com/mPHj29Af

bool avl_search_tree::avl_tree_node::rotate_left()
{
    if (_right_child != NULL) {
        avl_tree_node *new_root = _right_child;
 
        if (_parent != NULL) {
            if (_parent->_left_child == this) {
                _parent->_left_child = new_root;
            } else {
                _parent->_right_child = new_root;
            }
        }
 
        new_root->_parent = _parent;
        _parent = new_root;
 
        _right_child = new_root->_left_child;
        new_root->_left_child = this;
 
        if (_right_child != NULL) {
            _right_child->_parent = this;
        }
 
        //update heights
        update_height();
        new_root->update_height();
 
        return true;
    }
 
    return false;
}

Στη μέθοδο εισαγωγής μου σχολίασε το AVL εξισορρόπηση μέρος και όχι Είμαι απλώς προσπαθούν να περιστρέψετε το πρόσφατα εισαχθεί κόμβο προς τα αριστερά. Το αποτέλεσμα για την εισαγωγή ακέραιους σε αύξουσα σειρά: το δέντρο μου περιέχει μόνο την αρχική ρίζα (πρώτος κόμβος εισάγεται) και όλοι οι άλλοι κόμβοι διαρρεύσει.

Οποιαδήποτε βοήθεια στον εντοπισμό του προβλήματος εκτιμάται ιδιαίτερα ως αρχίζω να τρελαίνομαι.

Για την ιστορία: αν δεν χρησιμοποιείτε περιστροφές το δέντρο δεν θα διαρρεύσει κόμβους και λειτουργεί ως ένα κανονικό ισορροπημένη δυαδικό δέντρο αναζήτησης (για εισαγωγή και αναζήτηση).

Επεξεργασία: Λόγω σχόλιο AJG85 του εγώ θα προσθέσω τις παρατηρήσεις:

Πρόσθεσα printf «ελέγχους» με τη μέθοδο destructor της avl_search_tree :: avl_tree_node που θα εκτυπώσετε την τιμή του κλειδιού (στην περίπτωσή μου 32 ακέραιοι bit) πριν καθαρισμού και, με τη μέθοδο ένθετο της avl_search_tree που θα εκτυπώσει το κλειδί μόλις εισαχθεί.

Στη συνέχεια, το entrypoint του προγράμματος θα χορηγήσει avl_search_tree στο σωρό και προσθέστε τα κλειδιά για να σε αύξουσα σειρά και στη συνέχεια να το διαγράψετε.

Με ενεργοποιημένο το AVL Εξισορρόπηση παίρνω το ακόλουθο αποτέλεσμα στο τερματικό:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1

Πράγμα που σημαίνει thatall εισαγωγές ήταν επιτυχής, αλλά μόνο η ρίζα έχει διαγραφεί.

Με το AVL εξισορρόπηση σε σχόλια λειτουργεί σαν ένα κανονικό δυαδικό δέντρο αναζήτησης. Η έξοδος τερματικό είναι:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1
avl_search_tree::avl_tree_node::~avl_tree_node() : 2
avl_search_tree::avl_tree_node::~avl_tree_node() : 3
avl_search_tree::avl_tree_node::~avl_tree_node() : 4
avl_search_tree::avl_tree_node::~avl_tree_node() : 5
avl_search_tree::avl_tree_node::~avl_tree_node() : 6
avl_search_tree::avl_tree_node::~avl_tree_node() : 7
avl_search_tree::avl_tree_node::~avl_tree_node() : 8

Πράγμα που σημαίνει ότι όλα είναι σωστά καθαριστεί.

Τώρα ... πώς θα καταλήξει στο συμπέρασμα ότι οι μέθοδοι περιστροφής είναι τα θέματα; Υπό την σχολίασαν AVL εξισορρόπησης υπορουτίνα Ι προστίθεται μια γραμμή που περιστρέφεται κάθε πρόσφατα εισαχθεί κόμβο προς τα αριστερά. Το αποτέλεσμα? Το ίδιο όπως και αν η υπορουτίνα AVL Balancing έχει ενεργοποιηθεί.

Και όσον αφορά τη μέθοδο update_height (), δεν μεταβάλλει τη δομή του δέντρου με οποιονδήποτε τρόπο.

Ελπίζω ότι αυτό θα το αποσαφηνίσει.

Επεξεργασία 2:

Για να διευκρινιστούν κάποια περισσότερα πράγματα, αλλά είναι το πώς υλοποιείται η καταστροφέα avl_tree_node:

avl_search_tree::avl_tree_node::~avl_tree_node()
{
    printf(%s : %d\n, __PRETTY_FUNCTION__, *_key);

    if (_left_child != NULL) {
        delete _left_child;
    }

    if (_right_child != NULL) {
        delete _right_child;
    }

    if (_key != NULL) {
        delete _key;
    }
}

_left_child και _right_child είναι δείκτες σε avl_tree_node αντικείμενα που διατίθενται στο σωρό.

Επεξεργασία 3:

Χάρη στην 2η σχόλιο AGJ85 βρήκα το θέμα. Σε περιστροφή μεθόδους μου ξέχασα πως στην πραγματικότητα πρέπει να ενημερώσετε το δείκτη ρίζα του δέντρου με την νέα ρίζα, όταν η ρίζα μετατοπίστηκε.

Βασικά ρίζα του δέντρου ήταν πάντα δείχνουν προς την πρώτη εισαχθεί κόμβο και χωρίς ενημέρωση του δείκτη όταν χρειάζεται, περιστροφή μεθόδους μου θα διαρρεύσει ρίζα του νέου δέντρου που στην πραγματικότητα έχει ρυθμιστεί σωστά. :)

Σας ευχαριστούμε AGJ85!

Δημοσιεύθηκε 02/08/2011 στις 18:19
πηγή χρήστη
Σε άλλες γλώσσες...                            


3 απαντήσεις

ψήφοι
2

EDIT - Γαμώτο - δεν είχα δει ότι το θέμα έχει ήδη λυθεί (απάντηση στην ερώτηση). Ακόμα, ίσως υπάρχει μερικές συμβουλές για μη-απάντηση σε αυτό που αξίζει διάσωση.

Δεν έχουν ελεγχθεί διεξοδικά, αλλά νομίζω ότι θα πάμε λάθος σε αυτή τη γραμμή ...

_right_child = new_root->_left_child;

και ότι το πρόβλημα είναι ότι μπορεί να έχετε ήδη αντικατασταθεί new_root->_left_childστη γραμμή ...

_parent->_left_child = new_root;

Αυτό που νομίζω ότι θα πρέπει να κάνετε είναι, στην αρχή, έχουν ένα μπλοκ των τοπικών ορισμούς, όπως ...

avl_tree_node *orig_parent      = _parent;
avl_tree_node *orig_this        = this;
avl_tree_node *orig_left_child  = _left_child;
avl_tree_node *orig_right_child = _right_child;

Στη συνέχεια, χρησιμοποιήστε τις orig_τοπικές μεταβλητές, όπως τις πηγές για αργότερα αναθέσεις. Αυτό εξοικονομεί ένα ορισμένο ποσό της ανησυχείτε για τα δεδομένα ρέουν μέσω των διαφόρων δεικτών κατά τη διάρκεια της περιστροφής. Η βελτιστοποίησης πρέπει να απαλλαγούμε από κάθε περιττή εργασία αξίζει να ανησυχείτε για το αυτό, και δεν υπάρχουν πολλά αυτής της ούτως ή άλλως.

Ένα ζευγάρι των επιπλέον σημεία ...

Κατ 'αρχάς, η C ++ (και C) πρότυπα αποθεματικό αναγνωριστικά με κορυφαία υπογράμμισης, και με διπλό κάτω παύλες. Είναι ισχυρίστηκε ότι μπορείτε να πάρετε τις αλληλεπιδράσεις έκπληξη με το πρότυπο και compiler που παρέχονται από τις βιβλιοθήκες αν δεν σεβαστούμε αυτό - υποθέτω ότι θα πρέπει να είναι μακρο-συνδεδεμένα μέρη, για αναγνωριστικά μέλος, όμως. Να σύρει κάτω παύλες είναι ΟΚ - έχω την τάση να τα χρησιμοποιήσουν για να περιλαμβάνει φύλακες.

Μια κοινή σύμβαση για τις μεταβλητές μέλους είναι να προσθέσετε ένα ηγετικό mή m_. Ακόμη πιο συχνές, κατά πάσα πιθανότητα, δεν έχει καμία ιδιαίτερη πρόθεμα ή επίθεμα καθόλου.

Δεύτερον, μπορείτε (ή δεν μπορεί) να είναι ευκολότερο να εφαρμοστεί AVL δέντρα που δεν έχουν μητρική συνδέσεις αποθηκεύονται στους κόμβους. Δεν έχουν εφαρμόσει AVL δέντρα ακόμα τον εαυτό μου, αλλά έκανα την εφαρμογή κόκκινα-μαύρα δέντρα φορά. Μια σειρά από αλγόριθμους πρέπει να περιλαμβάνει μια αναδρομική αναζήτηση ως το πρώτο βήμα - δεν μπορείτε να κάνετε απλά μια τυπική αναζήτηση που θυμάται τον βρήκε κόμβο, αλλά απορρίπτει τη διαδρομή μέχρι τον κόμβο. Ωστόσο, αναδρομική εφαρμογή δεν είναι και τόσο άσχημα, και υπάρχουν λιγότεροι δείκτες να ταχυδακτυλουργία.

Τέλος, μια γενική συμβουλή - προσπαθούν να «στεγνό τρέχει» ένας αλγόριθμος, όπως αυτό μπορεί εύκολα να σας τρικλοποδιά εκτός και αν είναι απολύτως λειτουργήσει μέσα από αυτό το βήμα προς βήμα, και να ελέγξετε όλες τις πηγές πληροφοριών που είναι σχετικές (έχω ήδη τροποποιηθεί αυτό;) σε κάθε βήμα. Είναι πολύ εύκολο να πάρει στη συνήθεια του παρακάμπτοντας μερικά από τα στοιχεία για την ταχύτητα. Μια χρήσιμη μηχανή με τη βοήθεια δοκιμαστική λειτουργία είναι να εκτελέσετε τον κώδικα βήμα-βήμα σε ένα πρόγραμμα εντοπισμού σφαλμάτων, και να δούμε αν τα αποτελέσματα σε κάθε βήμα συμφωνούν με το χαρτί σας ξηρό επιχείρηση.

EDIT - ένα ακόμα σημείωμα - Δεν θα καλέσετε αυτό μια συμβουλή, γιατί δεν είμαι σίγουρος ότι σε αυτό το πλαίσιο. Συνήθως εφαρμογή κόμβους δομή δεδομένων με απλό Δομές - χωρίς απόκρυψη στοιχείων, λίγα, εάν υπάρχουν συναρτήσεις-μέλη. Το μεγαλύτερο μέρος του κώδικα διατηρείται χωριστά από τη δομή των δεδομένων, συχνά σε μια τάξη «εργαλείο». Ξέρω ότι αυτό σπάει το παλιό «το σχήμα η ίδια αντλεί» αρχή OOP, αλλά ΙΜΟ λειτουργεί καλύτερα στην πράξη.

Απαντήθηκε 02/08/2011 στις 20:34
πηγή χρήστη

ψήφοι
3

Χάρη στην 2η σχόλιο AGJ85 βρήκα το θέμα. Σε περιστροφή μεθόδους μου ξέχασα πως στην πραγματικότητα πρέπει να ενημερώσετε το δείκτη ρίζα του δέντρου με την νέα ρίζα, όταν η ρίζα μετατοπίστηκε.

Βασικά ρίζα του δέντρου ήταν πάντα δείχνουν προς την πρώτη εισαχθεί κόμβο και χωρίς ενημέρωση του δείκτη όταν χρειάζεται, περιστροφή μεθόδους μου θα διαρρεύσει ρίζα του νέου δέντρου που στην πραγματικότητα έχει ρυθμιστεί σωστά. :)

Απαντήθηκε 03/08/2011 στις 10:03
πηγή χρήστη

ψήφοι
1

Βλέπω έχετε βρει το σφάλμα που ψάχνατε στον κώδικά σας. (Όπως λέτε, δεν ήταν ενημέρωση του ρίζα δέντρου δείκτη στη νέα ρίζα, όταν άλλαξε η ρίζα. Είναι ένα κοινό πρότυπο για την λίστα και Εισαγωγή δέντρο / Διαγραφή μεθόδους για να επιστρέψει ένα δείκτη με τον επικεφαλής της λίστας ή ρίζα του δέντρου, και αν θυμάστε ότι το πρότυπο δεν θα κάνει και πάλι το λάθος.)

Σε υψηλότερο επίπεδο του άποψη, η τεχνική που έχω χρησιμοποιήσει για να αποφευχθούν προβλήματα με το AVL δέντρο ή κόκκινο-μαύρο δέντρο κώδικα είναι να χρησιμοποιήσετε αντί για ένα δέντρο ΑΑ , η οποία έχει παρόμοια απόδοση με αυτά, χρησιμοποιώντας O (n) χώρο και O (log n) χρόνο για την Εισαγωγή, Διαγραφή και αναζήτησης. Ωστόσο, AA δέντρα είναι σημαντικά πιο εύκολο να κώδικα.

Απαντήθηκε 04/08/2011 στις 16:55
πηγή χρήστη

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