2017-01-14 9 views
0

私はバイナリ検索ツリーデータ構造を実装しようとしています。バイナリ検索ツリークラスのinsert/insert_helperメソッドでツリーを初期化する際に問題があります。ポインタクラスのメンバは、クラスメソッドによる初期化後もNULLのままです

GDBを使用すると、insertメソッドへの最初の呼び出しでルートデータメンバーが初期化されていないことがわかります。なぜ私は、insert_helperメソッドへのポインタを渡しているので、私は期待しているので、メソッド自体の中でそのポインタを初期化できるはずです。基本的に、最初にinsert_helperの呼び出しでrootポインターを渡すと、クラスrootのメンバーを正しく初期化できないのはなぜですか? C++にはこれを許さないルールはありますか?

助けや助言が役に立ちます。関連するコードスニペットは以下のとおりです。

#ifndef BST_H_ 
#define BST_H_ 

#include <vector> 
#include <iostream> 
#include <exception> 

template <typename T> 
class Bin_Search_Tree { 
private: 
    typedef T value_type; 
    typedef T& reference; 
    typedef const T& const_reference; 
    typedef std::size_t size_type; 
    struct Node { 
    value_type data; 
    Node* left; 
    Node* right; 
    Node* parent; 
    }; 
    Node* root; 

    void free_tree(Node* rnode); 
    size_type size_helper(const Node* rnode) const; 
    Node* find_helper(const Node* rnode, const value_type& val) const; 
    void print_tree_helper(const Node* rnode) const; 
    bool insert_helper(Node* parent, Node* rnode, const value_type& val); 
    bool remove_helper(Node* rnode, const value_type& val); 
    Node* create_node(Node* parent, const value_type& val) const; 
    Node* get_min(const Node* rnode) const; 

public: 
    Bin_Search_Tree() : root(nullptr) { } 
    Bin_Search_Tree(const std::vector<value_type>& vals); 
    ~Bin_Search_Tree() { free_tree(root); } 

    bool empty() const { return (nullptr == root); } 
    size_type size() const { return size_helper(root); } 
    Node* find(const value_type& val) { return find_helper(root, val); } 
    bool insert(const value_type& val) { insert_helper(nullptr, root, val); } 
    bool remove(const value_type& val); 
    void print_tree() const { print_tree_helper(root); } 
}; 

template <typename T> 
bool Bin_Search_Tree<T>::insert_helper(Node* parent, Node* rnode, const value_type& val) { 
    if (nullptr == rnode) { 
    rnode = create_node(parent, val); 
    return true; 
    } else if (val == rnode->data) { 
    return false; 
    } else if (rnode->data < val) { 
    return insert_helper(rnode, rnode->right, val); 
    } else { 
    return insert_helper(rnode, rnode->left, val); 
    } 
} 

template <typename T> 
typename Bin_Search_Tree<T>::Node* Bin_Search_Tree<T>::create_node(Node* parent, const value_type& val) const { 
    Node* inode = new Node; 

    if (nullptr == inode) { 
    throw std::bad_alloc(); 
    } 
    inode->data = val; 
    inode->left = nullptr; 
    inode->right = nullptr; 
    inode->parent = parent; 
    return inode; 
} 
+1

'int 'なんかのものと同じように、*変更したいものにポインタ*を渡す必要があります。 – molbdnilo

+0

そして、初期化はコンストラクタの本体の前で行われます。その後、それは割り当てです。 – molbdnilo

+0

返信いただきありがとうございます。あなたは正しいです、問題は私が参照ではなく価値によって渡していることです。私はポインタ参照を必要とせずにクラスを更新して以来、少なくとも私はそれらを認識しています。ありがとう! –

答えて

0
関数で

最初
template <typename T> 
bool Bin_Search_Tree<T>::insert_helper(Node* parent, Node* rnode, const value_type& val) { 
    if (nullptr == rnode) { 
    rnode = create_node(parent, val); 
    return true; 
    } else if (val == rnode->data) { 
    return false; 
    } else if (rnode->data < val) { 
    return insert_helper(rnode, rnode->right, val); 
    } else { 
    return insert_helper(rnode, rnode->left, val); 
    } 
} 

root=nullptr、第1 if条件が満たされています。次に、

rnode = create_node(parent, val); 

を使用して新しいノードを作成します。ただし、rnodeは、値によってルートを渡すときに関数のローカルです。戻ると、ポインタが破棄され、割り当てたメモリにアクセスできなくなります。また、rootが指している場所は決して変更されていないので、そのままnullptrとなります。

これは、クラスのメンバ関数であるという事実を使用して簡単に行うことができます。つまり、rootメンバがその関数に表示されます。したがって、引数として渡す必要はありません。それは問題を解決するはずの関数の中で直接使用することができます。

+0

お返事ありがとうございます。そうです、問題は 'rnode'が関数のローカルなのです。上記のコメントのmolbdniloが指摘しているように、ポインタを値渡ししています。今日まで、私は参照によってポインタを渡すことを決して考えなかった。クラス自体が再帰的に定義されていないので、関数内で 'root'を直接使用することはできません(つまり、Node構造体の単なるラッパーです)。私はポインタ参照の必要性なしで動作するように再構成しました。助けてくれてありがとう。 –

関連する問題