Dlaczego mój kod C ++ nie usunąć wszystkie węzły w moim BST?

głosy
1

To ma przemierzać BST i usuwać każdy węzeł, w tym węzła głównego. Jednak na koniec, mam komunikat „korzeń ma jeszcze lewy węzeł”. Dlaczego nie są wszystkie węzły zostaną usunięte?

void deleteTree()
{   
    deleteNode(root);
    if(root->right)
        cout << root still has a right node << endl;
    if(root->left)
        cout << root still has a left node << endl;
    root = 0;

}   

void deleteNode(node *p) 
{   
    if(p->left) 
    {   
        deleteNode(p->left);
        p->left = 0;
    }   
    if(p->right) 
    {   
        deleteNode(p->right);
        p->right = 0;
    }   

    cout << Deleting node containing  << p->data << endl;
    delete p;
}   
Utwórz 11/02/2010 o 03:57
źródło użytkownik
W innych językach...                            


5 odpowiedzi

głosy
6

Twój usuwasz pna końcu ( root), a następnie próby uzyskania dostępu do jego zawartości w deleteTree(), gdzie rootnie wskazuje już przydzielonej pamięci. Efektem ma być niezdefiniowana.

Odpowiedział 11/02/2010 o 04:00
źródło użytkownik

głosy
2

Usuwasz root. A następnie kod próbuje uzyskać dostęp do pamięci, gdzie to było.

Jesteś dobrze się niezdefiniowany-behawioralnej ziemi tam.

Odpowiedział 11/02/2010 o 04:01
źródło użytkownik

głosy
2

Nie powinien dereference rootpo usunięciu go deleteNode. Używać debuggera aby sprawdzić, dlaczego root->leftjest niezerowe.

Odpowiedział 11/02/2010 o 04:01
źródło użytkownik

głosy
2

Widzisz root->leftpo już usunięty korzeń, dzięki czemu avalable do stosowania w nowej przydzielonego bloku.

Odpowiedział 11/02/2010 o 04:02
źródło użytkownik

głosy
-1

Chciałbym po prostu zmienić samego drzewa, byłoby łatwiej radzić sobie z nim wtedy:

struct Node
{
  Node(data_type data): mLeft(), mRight(), mData(data) {}
  Node(const Node& rhs): mLeft(), mRight(), mData(rhs.mData)
  {
    if (rhs.mLeft.get()) mLeft.reset(new Node(*rhs.mLeft));
    if (rhs.right.get()) mRight.reset(new Node(*rhs.mRight));
  }
  Node& operator=(Node rhs)
  {
    this->swap(rhs);
    return *this;
  }
  ~Node() { }

  void swap(Node& rhs)
  {
    using std::swap;
    swap(mLeft, rhs.mLeft);
    swap(mRight, rhs.mRight);
    swap(mData, rhs.mData);
  }

  Node* left() const { return mLeft.get(); }
  void left(std::auto_ptr<Node> node) { mLeft= node; }

  Node* right() const { return mRight.get(); }
  void right(std::auto_ptr<Node> node) { mRight = node; }

  data_type& data() { return mData; }
  const data_type& data() const { return mData; }

private:
  std::auto_ptr<Node> mLeft;
  std::auto_ptr<Node> mRight;
  data_type mData;
};

Będąc zorientowanym obiektowo, każdy węzeł jest teraz odpowiedzialny za pamięć to obsługuje. Ponadto, korzystając std::auto_ptrz interfejsu jasno wynika, że ma własności.

Zauważ, że to zostało dostosowane do głębokiego kopiowania, wszelkie inne podejście wymagające boost::shared_ptrlub równoważne. I tak std::auto_ptrpozostawia do czynienia z kopiowaniem przez siebie, żadnej magii tam.

Ta konstrukcja jest znacznie czystsze niż stosując zwykły C-structze każdy jest w stanie manipulować zasobów. Nadal masz pełny dostęp do podstawowych danych poprzez akcesor ... ale uważaj, aby nie wywołać niezdefiniowanej zachowanie ...

Oczywiście, nadal można zawiesić go:

Node& node = ...
delete node.left(); // haha

Ale jeśli C ++ może chronić przed przypadkowym kwestii, pozostawia otwarte drzwi do złego kodu.

Odpowiedział 11/02/2010 o 14:22
źródło użytkownik

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