2017-12-04 10 views
0

dies ist meine aktuelle AVLTree Implementierung avltree.h:Fehlerhafte AVLTree Implementierung C++

#pragma once 
#include <math.h> 
#include <algorithm> 
#include <iostream> 
namespace avltree { 

    template <class T> 
    struct node { 
     static node * null_node; 
     node *left = null_node; 
     node *right = null_node; 
     node *parent = null_node; 
     int height = 0; 
     T value; 
     node(T value) :value(value) {} 
     node(T value, int height) :height(height), value(value) {} 
    }; 
    template <class T> 
    node<T>* node<T>::null_node = new node(0, -1); 

    template <class T> 
    struct avltree { 
    public: 
     node<T> *root; 
     avltree(T value); 
     node<T> *insert(T value); 
     void print(void); 
     void print_with_height(void); 
    private: 
     node<T> *insert(T value, node<T> *x); 
     node<T> *left_rotate(node<T> *x); 
     node<T> *right_rotate(node<T> *x); 
     void retrace(node<T> *n); 
     void update_root(); 
     void print(node<T> *n); 
     void print(node<T> *n, int depth); 
     void update_height(node<T> *n); 
    }; 
    template <class T> 
    avltree<T>::avltree(T value) :root(new node<T>(value)) { } 

    template <class T> 
    node<T> *avltree<T>::insert(T value) { 
     auto n = insert(value, root); 
     update_root(); 
     return n; 
    } 
    template <class T> 
    void avltree<T>::retrace(node<T> *n) { 
     while (n != node<T>::null_node) { 
      update_height(n); 
      if (n->left->height - n->right->height > 1) { 
       if (n->left->left->height >= n->left->right->height) { 
        right_rotate(n); 
       } 
       else { 
        left_rotate(n); 
        right_rotate(n); 
       } 
      } 
      else 
       if (n->right->height - n->left->height > 1) { 
        if (n->right->right->height >= n->right->left->height) { 
         left_rotate(n); 
        } 
        else { 
         right_rotate(n); 
         left_rotate(n); 
        } 
      } 
      n = n->parent; 
     } 
    } 
    template <class T> 
    node<T> *avltree<T>::insert(T value, node<T> *n) { 
     if (n->value > value) { 
      if (n->left != node<T>::null_node) { 
       n->left->height++; 
       insert(value, n->left); 
      } 
      else { 
       auto new_node = new node<T>(value); 
       n->left = new_node; 
       new_node->parent = n; 
       retrace(n); 
       return new_node; 
      } 
     } 
     if (n->value < value) { 
      if (n->right != node<T>::null_node) { 
       n->right->height++; 
       insert(value, n->right); 
      } 
      else { 
       auto new_node = new node<T>(value); 
       n->right = new_node; 
       new_node->parent = n; 
       retrace(n); 
       return new_node; 
      } 
     } 
     update_height(n); 
     return n; 
    } 
    template <class T> 
    node<T> *avltree<T>::left_rotate(node<T> *x) { 
     node<T> *y = x->right; 
     if (y == node<T>::null_node) { 
      return node<T>::null_node; 
     } 
     y->parent = x->parent; 
     if (x->parent->right == x) { 
      x->parent->right = y; 
     } 
     else { 
      x->parent->left = y; 
     } 

     y->left = x; 
     x->parent = y; 

     x->right = y->left; 
     x->right->parent = x; 

     update_height(x); 
     update_height(y); 

     return x; 
    } 
    template <class T> 
    node<T> *avltree<T>::right_rotate(node<T> *x) { 
     node<T> *y = x->left; 
     if (y == node<T>::null_node) { 
      return node<T>::null_node; 
     } 
     y->parent = x->parent; 
     if (x->parent->right == x) { 
      x->parent->right = y; 
     } 
     else { 
      x->parent->left = y; 
     } 

     y->right = x; 
     x->parent = y; 

     x->left = y->right; 
     x->left->parent = x; 

     update_height(x); 
     update_height(y); 

     return x; 
    } 
    template <class T> 
    void avltree<T>::update_root() { 
     auto n = root, last = root; 
     while (n != node<T>::null_node) { 
      last = n; 
      n = n->parent; 
     } 
     root = last; 
    } 
    template <class T> 
    void avltree<T>::print(void) { 
     print(root); 
     cout << endl; 
    } 
    template <class T> 
    void avltree<T>::print(node<T> *n) { 
     if (n->left != node<T>::null_node) { 
      print(n->left); 
     } 
     cout << n->value << " "; 
     if (n->right != node<T>::null_node) { 
      print(n->right); 
     } 
    } 
    template <class T> 
    void avltree<T>::print(node<T> *n, int height) { 
     if (n->left != node<T>::null_node) { 
      print(n->left, height); 
     } 
     if (n->height == height) { 
      std::cout << n->value << ", "; 
     } 
     if (n->right != node<T>::null_node) { 
      print(n->right, height); 
     } 
    } 
    template <class T> 
    void avltree<T>::print_with_height(void) { 
     int height = root->height; 
     for (int height = root->height; height >= 0; height--) { 
      std::cout << "height = " << height << "\t:"; 
      print(root, height); 
      std::cout << std::endl; 
     } 
     std::cout << std::endl; 
    } 
    template <class T> 
    void avltree<T>::update_height(node<T> *n) { 
     n->height = std::max(n->left->height, n->right->height) + 1; 
    } 
} 

und folgende Hauptdatei:

#include "stdafx.h" 
#include "avltree.h" 

int main() 
{ 
    avltree::avltree<int> tree(1); 
    for (int i = 2; i < 128; i++) { 
     tree.insert(i); 
    } 
    tree.print_with_height(); 

    return 0; 
} 

Das Problem mit obigem Code ist, dass es bei der Iteration 124 erzeugt eine Endlosschleife innerhalb des Rücklaufaufrufs in der Einfügung. Grundsätzlich werden die Knoten so rotiert, dass der Wurzelknoten nicht erreicht werden kann (was zu einer Endlosschleife führt). Ich habe die trivialen Beispiele (für ein paar Knoten) überprüft und sie funktionieren. Alles für einen Lauf ist vorgesehen, ich würde mich freuen, wenn jemand mit Erfahrung in avltrees sich Zeit nehmen und dieses Programm ausführen könnte, vielleicht herauszufinden, was schief läuft innerhalb von Rücklauf/Umdrehungen.

+0

Wenn Sie den Fehler zuverlässig zu einem bestimmten Zeitpunkt replizieren können (z. B. 'i == 124'), können Sie die Ausführung an diesem Punkt innerhalb eines Debuggers anhalten und Code Zeile für Zeile durchlaufen, um zu sehen, was passiert und was das Problem sein könnte. [Bitte lernen Sie, wie Sie Ihre Programme debuggen können] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). –

+0

Sie haben einen Plan im Kopf. Sie wissen, wo der Code falsch läuft. Beginnen Sie mit der Fehlersuche, bei der der Code falsch läuft, d. H. Wo er gegen den Plan verstößt, den Sie hatten. Wenn der ursprüngliche Plan einen Fehler aufweist, wiederholen Sie den Plan und rekodieren Sie ihn. Schreiben Sie niemals ein vollständiges Programm mit nur einem Teil dessen, was Sie genau machen sollten und dann hoffentlich den Rest durch Verschieben oder Einfügen von Variablen und Funktionen herausfinden. – PaulMcKenzie

Antwort

1

Eine solche Endlosschleife weist auf ein wahrscheinliches Problem mit Ihren Rotationsfunktionen hin. Ein kurzer Blick auf left_rotate zeigt

y->left = x; 
    x->parent = y; 

    x->right = y->left; 

Was y->left in dieser letzten Aufgabe ist? x, also was du wirklich bist ist x->right = x. Dies ist eindeutig ein Problem, das behoben werden muss.

Ein ähnliches Problem existiert in right_rotate.