我正在使用二元搜索树,订单很重要。
如果节点/节点被修改,则树需要更新以保持顺序正确。
我想要做的是重载访问方法,例如preOrderTraversal
;这样就可以区分该函数是否会修改节点。
void preOrderTraversal(std::function<void(Type)> visit); // read only visit
和
void preOrderTraversal(std::function<void(Type &)> visit); // write visit, update needed afterwards
如果传入的std::function
是值参数类型,则表示只读访问,因此无需更新树;如果std::function
是引用类型,则将修改树,因此需要调用update
方法。
我知道我可以将preOrderTraversal
方法标记为const
和非const
重载。但是,如果我们知道函数传入是否可以更改树节点并重载它们,那么会很清楚吗?
template<typename Type>
class BinaryTree {
public:
struct Node {
Type data;
Node* left{ nullptr };
Node* right{ nullptr };
Node(Type && value) : data{ std::move(value) } { }
Node() = delete;
};
// ... omit unrealated parts ...
// head, left leaf, right leaf
// value type, tree will not be modified
void preOrderTraversal(std::function<void(Type)> visit) {
std::cout << "void preOrderTraversal(std::function<void(Type)>)" << std::endl;
preorder_utility(visit);
}
// reference type, tree will be modified; so the tree need update order of nodes.
void preOrderTraversal(std::function<void(Type&)> visit) {
std::cout << "void preOrderTraversal(std::function<void(Type&)>)" << std::endl;
preorder_utility(visit);
update(); // update function to keep the tree in binary search tree order.
}
private:
template <typename Function>
void preorder_utility(Function visit) {
if( nullptr == root ) return;
std::stack<Node*> stack;
stack.push(root);
while( !stack.empty() ) {
auto node = stack.top();
stack.pop();
visit(node->data);
if( node->right ) {
stack.push(node->right);
}
if( node->left ) {
stack.push(node->left);
}
}
}
Node* root{nullptr};
};
这样我们就可以有访问函数可以修改树了。
// just as an example, readonly can not change the tree,
// while write may change the tree
void readonly(double value) {
// value inside tree will not change
value += 10.0;
std::cout << value << std::endl;
}
void write(double & value) {
// value inside tree will change
value += 10.0;
std::cout << value << std::endl;
}
所以
int main() {
BinaryTree<double> btree;
// ... working on the tree..., push, pop, etc.
btree.preOrderTraversal(readonly);
btree.preOrderTraversal(write);
}
[更新]
看起来如果我使readonly
采用rvalue-reference,代码将编译并运行。
// this will call void preOrderTraversal(std::function<void(Type)> visit)
// hence no update method will be called.
void readonly(double && value) {
// value inside tree will not change
value += 10.0;
std::cout << value << std::endl;
}