C++;:指向数据成员或特征的指针? 我在C++中使用了一些二叉树算法,并试图尽可能地编写通用代码。特别是,我希望我的函数(算法)能够对任何(当然,在某种程度上)树状数据结构进行操作
树节点结构可以用不同的方式定义,例如:C++;:指向数据成员或特征的指针? 我在C++中使用了一些二叉树算法,并试图尽可能地编写通用代码。特别是,我希望我的函数(算法)能够对任何(当然,在某种程度上)树状数据结构进行操作,c++,templates,c++11,C++,Templates,C++11,树节点结构可以用不同的方式定义,例如: struct binary_tree_node { int data; struct binary_tree_node *left; struct binary_tree_node *right; }; 或者像这样: struct binary_tree_node2 { long key; struct binary_tree_node2 *first_child; struct binary_tree_n
struct binary_tree_node
{
int data;
struct binary_tree_node *left;
struct binary_tree_node *right;
};
或者像这样:
struct binary_tree_node2
{
long key;
struct binary_tree_node2 *first_child;
struct binary_tree_node2 *second_child;
};
或者其他的,但和这个模式很相似。
因此,我希望我的函数/算法能够处理这些或类似的数据结构
例如,以下是我如何定义一个简单函数:
template <typename TreeNode, typename DataType = typename TreeNode::data_type>
TreeNode*
binary_tree_new_node(DataType value = DataType(),
DataType TreeNode::* data = &TreeNode::data,
TreeNode* TreeNode::* left = &TreeNode::left,
TreeNode* TreeNode::* right = &TreeNode::right)
{
TreeNode *newnode = new TreeNode();
newnode->*data = value;
newnode->*left = nullptr;
newnode->*right = nullptr;
return newnode;
}
这里有哪些可用选项?
这有什么意义吗?:)
提前感谢STL集合库的工作方式是树库的作者将提供节点类,这样模板的所有用户需要做的就是提供数据。另一个你想要的选择是侵入式的数据结构(这对于谷歌来说是一个很好的概念术语)。对于这些成员,您有两个选择,第一个是要求数据成员为左、右和右数据。其次,需要具有特定名称的访问函数,以便模板可以找到它们。第三,需要将functor作为模板参数传入,以便您可以使用它们查找所需的数据。我个人认为STL方法最不混乱,其次是函子方法。为了使算法尽可能通用,我建议使用函子。您的二叉树新节点如下所示
template<typename G, typename L, typename R, typename AT, typename AD, typename D>
auto binary_tree_new_node(
G generator,
L left,
R right,
AT assign_tree,
AD assign_data,
D data) ->decltype( generator() )
{
auto tree = generator();
auto& l = left(tree);
auto& r = right(tree);
assign_data(tree, data);
assign_tree(l, nullptr);
assign_tree(r, nullptr);
return tree;
}
除了支持不同名称的字段外,您的代码似乎不太通用。它不支持使用
unique\u ptr
或shared\u ptr
存储其子级的树,也不支持子级使用弱\u ptr
指向其父级的树,也不支持树将其子级存储在std::vector
中的树,或其他无数变体。我不想直接在树上操作,而是想找到一些原始操作并对它们进行操作。那么这些原始操作是否依赖于特征
任何类型…@Yakk*\u ptr有什么问题std::vector
使它不仅仅是一个二叉树。关于基本操作的想法听起来不错,但对于基本的二叉树,它只是遵循左或右子级。因此,我指出了您的设计存在缺陷的4种方式(唯一的\u ptr
,共享的\u ptr
,当它们被修改时想要做某事的节点,可能的指针存储直到需要时才存在),你已经回应了其中一个。其他3个不足以扔掉你的设计吗?对于std::vector
,N元树支持所有的二叉树操作(set/get first child、set/get second child、set/get node data),因此一个好的二叉树抽象应该能够将创建一个N元树包装为二进制:您不能,这表明你的抽象性很差。@Yakk我不是想在这里建立一个完美的抽象,而是问如何改进一个特定的东西。不过,感谢您的想法和反馈,我真的很感激。我不会完全同意“树库的作者将提供节点类”这一部分。通过这样做,如果必须使用node类,作者将算法绑定到该类,这实际上与将算法定义为该类的方法相同,这(至少据我所知)不是STL/boost或类似LIB应该采用的方式。@alveko您标准列表的用户从未定义列表节点。这同样适用于Map或需要使用节点的任何其他标准容器。节点是在容器内部定义的。如果您在VS2012中,请打开列表标题并搜索struct\u list\u节点。它为数据定义了一个节点结构,其中包含_Next _Prev和_Myval。
template<typename G, typename L, typename R, typename AT, typename AD, typename D>
auto binary_tree_new_node(
G generator,
L left,
R right,
AT assign_tree,
AD assign_data,
D data) ->decltype( generator() )
{
auto tree = generator();
auto& l = left(tree);
auto& r = right(tree);
assign_data(tree, data);
assign_tree(l, nullptr);
assign_tree(r, nullptr);
return tree;
}
// WARNING!!! Very dangerous code!!!
binary_tree_node* generator()
{
return new binary_tree_node;
}
binary_tree_node*& left(binary_tree_node* tree)
{
return tree->left;
}
binary_tree_node*& right(binary_tree_node* tree)
{
return tree->right;
}
void assign_data(binary_tree_node* node, int data)
{
node->data = data;
}
void assign_tree(binary_tree_node*& node, binary_tree_node* data)
{
node = data;
}