使用模板和模板继承将节点插入二进制搜索树的困难

时间:2017-09-04 21:15:05

标签: c++ c++11 pointers binary-tree binary-search-tree

我正在处理的是我创建了3个模板类。我正在尝试为二进制树创建一个库,尽管我对C ++知之甚少。我使用结构在C中实现了二叉树,但这次我想利用C ++提供的面向对象编程,所以我为节点,二叉树和二叉搜索树创建了类。

如果有其他错误而我没有注意到,我会更自如地显示所有代码。所以这就是。 (注意:正在使用C ++ 11)

node_class.h

template <typename key_type, typename value_type>
class node_class {
public:
    node_class(key_type key, value_type value) {
        SetKey(key);
        SetValue(value);
        SetLeft(nullptr);
        SetRight(nullptr);
    }
    void SetKey(key_type key) {
        this->key = key;
    }
    void SetValue(value_type value) {
        this->value = value;
    }
    void SetLeft(node_class <key_type, value_type> *left) {
        this->left = left;
    }
    void SetRight(node_class <key_type, value_type> *right) {
        this->right = right;
    }
    key_type GetKey() {
        return this->key;
    }
    value_type GetValue() {
        return this->value;
    }
    node_class <key_type, value_type> *GetLeft() {
        return this->left;
    }
    node_class <key_type, value_type> *GetRight() {
        return this->right;
    }
private:
    key_type key;
    value_type value;
    node_class <key_type, value_type> *left;
    node_class <key_type, value_type> *right;
};

binary_tree_class.h

template <typename key_type, typename value_type>
class binary_tree_class {
public:
    binary_tree_class() {
        SetRoot(nullptr);
    }
    // ...
protected:
    void SetRoot(node_class <key_type, value_type> *root) {
        this->root = root;
    }
    node_class <key_type, value_type> *GetRoot() {
        return this->root;
    }
private:
    node_class <key_type, value_type> *root;
    // ...
};

binary_search_tree_class.h

template <typename key_type, typename value_type>
class binary_search_tree_class : public binary_tree_class <key_type, value_type> {
public:
    binary_search_tree_class() {

    }
    void Insert(key_type key, value_type value) {
        Insert(key, value, this->GetRoot());
    }
    void Insert(key_type key, value_type value, node_class <key_type, value_type> *node) {
        if (node == nullptr) {
            node = new node_class <key_type, value_type> (key, value);
        }
        if (key > node->GetKey()) {
            Insert(key, value, node->GetRight());
        } else if (key < node->GetKey()) {
            Insert(key, value, node->GetLeft());
        }
    }
    // ...
};

就插入函数而言,我读到我必须通过引用传递node参数,以便对树进行更改(如果我错了,请纠正我)。话虽如此,我必须从这个

更改函数protorype
void Insert(key_type key, value_type value, node_class <key_type, value_type> *node)

进入这个

void Insert(key_type key, value_type value, node_class <key_type, value_type> *&node)

在我这样做后,我完全无法弄清楚出了什么问题,所以我仍然坚持使用g ++中的以下错误

In file included from main.cpp:1:0:
binary_search_tree_class.h: In instantiation of ‘void binary_search_tree_class<key_type, value_type>::Insert(key_type, value_type) [with key_type = int; value_type = int]’:
main.cpp:5:31:   required from here
binary_search_tree_class.h:11:9: error: invalid initialization of non-const reference of type ‘node_class<int, int>*&’ from an rvalue of type ‘node_class<int, int>*’
   Insert(key, value, this->GetRoot());
         ^
binary_search_tree_class.h:13:7: note:   initializing argument 3 of ‘void binary_search_tree_class<key_type, value_type>::Insert(key_type, value_type, node_class<key_type, value_type>*&) [with key_type = int; value_type = int]’
  void Insert(key_type key, value_type value, node_class <key_type, value_type> *&node) {

在上面的文件中,我无法编写include指令,因为#符号导致缩进问题,但我认为你得到它。

1 个答案:

答案 0 :(得分:5)

问题

问题从方法开始:

node_class<>* binary_search_tree<>::GetRoot();

它返回变量成员root副本指针。

换句话说,当您调用方法GetRoot()时,您将获得root节点的地址位置,并可能将该地址保存到另一个指针变量中。

只是为了给你一个主意。让我们假设存储器中某处有根节点:

 0x01 [...]
 0x02 [RootNode]
 0x03 [...]

您的二叉树将保留根节点的地址并将其存储在指针中(无论如何都是一个变量)。

布局内存将类似于:

0x01 [...]
0x02 [RootNode]
0x03 [...]
0x04 [binary_tree::root = 0x02]

让我们假设我们调用以获取根地址:GetRoot()它实际上将返回RootNode的地址和而不是对成员变量{{的引用1}} 指向binary_tree:root

所以当您使用:

调用RootNode
GetRoot()

布局内存将类似于:

void foo() {
  auto p = binary_tree.GetRoot();
}

正如您在方案中所看到的,0x01 [...] 0x02 [RootNode] 0x03 [...] 0x04 [binary_tree::root = 0x02] 0x05 [...] 0x06 [p = 0x2] p(变量成员)的副本,但它们实际上是两个不同指针实际指向相同的位置内存。

因此,如果您将root作为引用传递给修改它的函数,那么p将被修改,但不会修改成员变量p

方案和代码非常简洁,但我希望它们能帮助您了解情况。 ::root的作用类似于复制成员变量,而不是返回对它的引用。

您的编译错误来自于您实际上并未将返回的复制的地址保存到另一个指针中,而是直接将其作为参数传递。因此,会创建临时表达式并将其传递给方法GetNode()。但是,临时表达式无法通过内存中的某个位置进行标识,因此您无法从中获取引用,这就是您的编译器无法从临时值中获取引用的原因。

如何解决?

有几种方法可以解决这个问题。

我认为你可以改变你的类设计:只需要成员变量 protected 就可以访问。这样,您就可以获得“真实”指针,而不是复制地址值。

简单的建议

  • 这可能是个人的,但我认为带指针引用的符号是不可读的。 如果你的函数(或方法)需要修改指针的地址,只需使用:Insert(指向指针的指针)。

  • void foo(node_class**)添加到每个名称类是非常多余的,使代码更加冗长。班级名称应为_class