C++ - Problem z BST

0

Witam, mam do napisania funkcję wstawiania do drzewa BST, napisałem dwie różne na podstawie książki i materiałów dostępnych w internecie i coś mi nie działa. Nie wiem czy to wina tego, że nie pisze tego na klasach, bo we wszystkich źródłach jest to tak rozpisane, ale niestety moje umiejętności są zbyt niskie, żeby coś takiego zbudować. Proszę o pomoc w znalezieniu błędu

pierwszy program

 #include <iostream>

using namespace std;
struct wezelek
{
   wezelek *lewy,*prawy;
   int key;
};

wezelek* wstaw(wezelek* wezel, int liczba)
{
    if (wezel->key==0)
    {
       
        wezel->key=liczba;
        wezel->lewy=NULL;
        wezel->prawy=NULL;
    }
    else if (liczba<wezel->key)
    wstaw(wezel->lewy,liczba);
    else wstaw(wezel->prawy,liczba);
    return wezel;
}

int main()
{
wezelek *wezel=new wezelek;
wezel->key=0;
  wstaw(wezel,10);
  wstaw(wezel,20);
  wstaw(wezel,3);
  wstaw(wezel,15);
  wstaw(wezel,7);
    return 0;
}

drugi

 #include <iostream>

using namespace std;
struct wezelek
{
   wezelek *lewy,*prawy,*rodzic;
   int key;
};

wezelek* wstaw(wezelek* root, wezelek* z)
{
   wezelek *y,*x=new wezelek;
   y=NULL;
   x=root;
   while(x)
   y=x;
   if(z->key<x->key)
        x=x->lewy;
   else x=x->prawy;
   z->rodzic=y;
   if (y==NULL)
        root=z;
   else if (z->key<y->key)
        y->lewy=z;
   else y->prawy=z;
   return y;
}

int main()
{
    wezelek *root;
    int tab[5]={3,4,5,2,7};
    for (int i=0;i<5;i++)
    {
        wezelek *z=new wezelek;
        z->key=tab[i];
        z->lewy=NULL;
        z->prawy=NULL;
        z->rodzic=NULL;
        wstaw(root,z);
    }

      return 0;
}
0

Już to robisz na klasach (w pewnym sensie) - bo w C++ klasa i struktura to niemal to samo. Różnica polega na tym, że struktura ma domyślnie publiczne dane (klasa prywatne) i domyślnie publicznie dziedziczy (klasa prywatnie).

W pierwszym programie, wycinek z funkcji wstaw():

        wezel->key=liczba;
        wezel->lewy=NULL;
        wezel->prawy=NULL;

To powinno być w konstruktorze, najlepiej w formie listy inicjalizacyjnej.

Poza tym prześledź tę funkcję. W funkcji zakładasz, że wezel jest wskaźnikiem na zaalokowaną pamięć. Przyjmijmy, że to pierwsze wywołanie z main():
1.

if (wezel->key==0)
  • tak, bo wyzerowałeś w main() (ale to znaczy, że Twoje drzewo nie potrafi przechowywać wartości zera!)
      {
        wezel->key=liczba;
        wezel->lewy=NULL;
        wezel->prawy=NULL;
    }

Okej, masz ustalone wartości, lewy i prawy wyzerowane, wygląda w porządku. (Powiedzmy).
3. return wezel; Reszta rozgałęzień zostaje pominięta.
Wywołujesz wstaw() drugi raz:
4.

if (wezel->key==0)
  • nie, bo przed chwilą wartość została ustawiona na coś innego.
  1. Załóżmy, że liczba którą dodajesz jest mniejsza od tej w korzeniu, wywołujesz więc wstaw(wezel->lewy, liczba); gdzie wezel->lewy ma wartość NULL (powoli radziłbym się przestawiać na nullptr. Można sobie go napisać - jest też na More C++ Idioms wiki - nawet jeśli Twój kompilator go jeszcze nie obsługuje).
if (wezel->key==0)

Kaboom!wezel ma wartość 0, nie wskazuje na żaden obiekt w pamięci. Zaczynasz zauważać problem?

Z drugiego:

   wezelek *y,*x=new wezelek; // po co alokujesz nowy wezelek...
   y=NULL;
   x=root; // ...chyba tylko po to, żeby mieć tu wyciek pamięci?

Może jednak warto poczytać o konstruktorach i obiektowości ogólnie? Nie zaszkodzi chyba też o ręcznym zarządzaniu pamięcią. Łatwiej Ci będzie zrozumieć przykłady.
Tutaj wycinek z szablonu klasy SortTree:

template <typename T>
class SortTree {
public:
    typedef unsigned long size_type;
protected:
    struct Node {
        T data;
        Node* left;
        Node* right;

        Node(const T& data) : data(data), left(nullptr), right(nullptr) {}
    };
    
    Node* root;
    size_type tree_size;
    bool unique;
//...
    void insert(Node*& root, const T& data) {
        if (root == nullptr) {
            root = new Node(data);
            ++tree_size;
        } else {
            if (data < root->data) {
                insert(root->left, data);
            } else {
                if ((unique && data > root->data) || !unique) {
                    insert(root->right, data);
                }
            }
        }
    }
//...
}

gdzie unique == true oznacza, że jeżeli wartość dodawana do drzewa już w nim istnieje - nie zostanie dodana.

http://math.hws.edu/eck/cs225/s03/binary_trees/
http://cslibrary.stanford.edu/110/BinaryTrees.html

1

Dziękuję za wyczerpującą odpowiedź :) Rzeczywiście pogubiłem się z tymi wskaźnikami. Poprawiłem obydwa programy i już wszystko działa.
Jeszcze raz dzięki!

1 użytkowników online, w tym zalogowanych: 0, gości: 1