有两个整数x和7是随机生成的整数。该程序使用红黑树成员fucntion插入将新值插入树中。
我不理解插入函数的参数,更具体地说是
的使用(void*)x and (void*y)
这是main
中的函数调用rbt.rbtree_insert(t, (void*)x, (void*)y, compare_int);
这是定义的插入函数
void RBTree::rbtree_insert(rbtree t, void* key, void* value, compare_func compare)
{
node inserted_node = new_node(key, value, RED, NULL, NULL);
if (t->root == NULL)
{
t->root = inserted_node;
}
else
{
node n = t->root;
while (1)
{
int comp_result = compare(key, n->key);
if (comp_result == 0)
{
n->value = value;
return;
}
else if (comp_result < 0)
{
if (n->left == NULL)
{
n->left = inserted_node;
break;
}
else
{
n = n->left;
}
}
else
{
assert(comp_result > 0);
if (n->right == NULL)
{
n->right = inserted_node;
break;
}
else
{
n = n->right;
}
}
}
inserted_node->parent = n;
}
insert_case1(t, inserted_node);
verify_properties(t);
}
答案 0 :(得分:0)
void*
是一种类型。更具体地说,它是指针类型。更具体地说,它是special pointer类型,可以指向任何类型。 void*
是一种在C中实现polymorphism的方法。通常不建议在C ++中使用void*
。
(void*)x
是一个explicit type conversion,也称为C风格的类型转换表达式。变量x
的类型将转换为void*
。在C ++中不鼓励使用C风格的演员表。
大概x
的类型不是void*
,因此需要进行转换才能匹配参数的类型。
答案 1 :(得分:0)
此代码的作者使用C ++中提供的最抽象的指针类型:void*
。这是一个指针,所以“东西”。这个“东西”可能在编译时没有定义。 (void*)x
是遗留C语法中的类型转换,它将任何其他指针解释为void*
。首选的C ++语法是static_cast<void*>(x)
,但只有void*
才应该使用,当有非常好的理由时这样做。
我理解,这是遗留代码,您被要求继续工作。所以坦率地说,它存在很多错误。
实现红黑树类有两个原因:学习数据结构和std::map<>
作为标准库实现的一部分。在所有其他情况下,没有理由不喜欢std::map<>
。它可以帮助你摆脱所有的设计陷阱,这段代码的作者介入了。
将类的名称添加到成员函数的名称是多余的。称之为RBTree::insert()
而不是RBTree::rbtree_insert()
。当您为不同的容器类型使用一致的成员函数名称时,您可以在将来轻松地交换它们,而无需更改对所有成员函数的所有调用。标准容器是这里的一个很好的灵感来源。
红黑树实例始终必须使用相同的比较功能。要一次又一次地将比较功能传递给insert()
,find()
,erase()
等不仅多余而且容易出错。将它作为构造函数的参数,或者更好地作为红黑树类模板的模板参数。
在任何情况下,红黑树都应该是一个模板,它有一个键和一个值类型作为模板参数。然后,insert()
,find()
等所有成员函数都可以是类型安全的。
为什么要将此对象显式传递给成员函数。我想,该代码的作者一直在尝试用C ++编写Python。在C ++中,this
对于成员函数始终是隐式的,与Python中的self
不同。
总而言之,我建议使用这样的界面:
template<typename key_t,
typename value_t,
typename Compare = std::less<key_t>>
class rb_tree {
void insert(const key_t& key, const value_t& value);
void erase(const key_t& key);
value_t find(const key_t& key);
};
如您所见,我们现在定义键和值的类型,并在insert()
,erase()
和find()
中使用它们。这些函数永远不会尝试使用int
键遍历树,就好像它有std::string
个键一样。它们也总是使用相同的比较函数,默认为运算符<
。
使用起来要好得多:
rb_tree<int, int> rbt; // we use the default comparison
int x = 42;
int y = 4711;
rbt.insert(x, y);
assert(rbt.find(x) == y);
rbt.erase(x);
嗯,实际上我真正的建议是放弃本土的红黑树,而是使用std::map<>
。它的用法更直观:
std::map<int, int> rbt;
int x = 42;
int y = 4711;
rbt[x] = y;
assert(rbt[x] == y);
rbt.erase(x);