なぜC ++のコードでは、私のBST内のすべてのノードを削除するには失敗していますか?

StackOverflow https://stackoverflow.com/questions/2241949

質問

これは、ルートノードを含む、BSTを横断し、すべてのノードを削除することになっています。しかし、最後に、私はメッセージ「ルートはまだ左のノードを持っている。」取得しますなぜ、すべてのノードが削除されていない?

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;
}   
役に立ちましたか?

解決

あなたはp、割り当てられたメモリへのrootもはやポイントで、その内容にアクセスしようとし、その後エンド(deleteTree())でrootを削除しています。結果は未定義されようとしている。

他のヒント

あなたはrootを削除しています。そして、あなたのコードは、それがあった場所のメモリにアクセスしようとしてます。

あなたが未定義の行動の地にもしている。

あなたはrootでそれを削除した後間接参照deleteNodeべきではありません。 root->leftが非nullである理由を検査するデバッガを使用します。

あなたはすでに新しい割り当てられたブロックで使用できるようになり、ルートを削除した後にあなたがroot->leftを見ている。

私は単にツリー自体を変更するだろう、それに対処しやすくなります:

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

オブジェクト指向であることによって、各ノードは、今、それが扱うメモリの責任です。また、インタフェースのstd::auto_ptrを使用すると、それが明確にそれが所有権を取得することになります。

それは、ディープコピーのためboost::shared_ptrまたは同等を必要とする他のアプローチを調整されていますので注意してください。そして、そうstd::auto_ptrは、あなたが自分でコピーを扱う残し、そこにはマジックます。

このデザインは、誰もがリソースを操作することができることで、プレーンC-structを使用するよりもはるかクリーナーです。あなたはまだ、アクセサを経由して、基礎となるデータへのフルアクセスを持っている...しかし、彼らは未定義の動作を起動しないように注意してください...

もちろん、あなたはまだそれをダウンクラッシュすることがあります:

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

しかし、C ++が意図しない問題に対して保護することができるならば、それは邪悪なコードへのオープンドアを残しています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top