我写完了一个AVL树,编程时困扰我的一件事就是决定哪些方法属于哪个类:
template <class ValueType,class CompareFunction>
class avlTree{
class avlTreeException{};
public:
class ElementDoesntExist : public avlTreeException{};
class EmptyTree : public avlTreeException{};
class ElementAlreadyExists : public avlTreeException{};
private:
class Node{
friend class avlTree;
ValueType* data;
Node *sonA,*sonB,*dad;
int height,balance;
private:
CompareFunction compare;
int treeSize;
Node* root;
};
(我删除了public \ private方法以节省空间)。
对于某些方法,我认为我做出了正确的选择:更新是Node的一种方法(更新高度等)。
插入/删除是树的功能。
但是例如树析构函数使用的函数destroyNodeTree(Node*)
。我所做的就是destroyNodeList()
致电destroyNodeTree(root)
template <class ValueType,class CompareFunction>
void avlTree<ValueType,CompareFunction>::avlTree::destroyNodeTree(Node* rooty) {
if(!rooty){
return;
}
Node *A=rooty->sonA,*B = rooty->sonB;
destroyNodeTree(A);
destroyNodeTree(B);
}
但是,我本可以使destroyNodeTree()
成为Node的方法,并在析构函数的根上调用它(它将以相同的方式实现)。
我有一个类似的问题决定方法findNode(const ValueType&)
应该去哪里,这意味着它显然是树的公共方法,但是我应该为具有相同名称的Node创建一个方法并让树函数调用节点根上的方法?拥有一个公共函数和一个具有相同名称的内部类方法是否可以接受?
在我看来,最好将它作为节点的方法,因为它提供了更大的灵活性(我将能够仅在某个节点下搜索节点),但另一方面,这意味着该方法要么需要创建class compare
的实例,或者让每个节点保留实例的副本,或者将class compare
作为静态函数。在我看来,每个都有一个缺点:创建一个实例可能是昂贵的,保持副本可能是昂贵的,并迫使用户使该功能静态似乎不适合我(但我非常缺乏经验,所以修复我,如果我错了。)
在任何情况下,我最终只使findNode成为一个treeFunction而不是一个方法(硬件分配不需要树能够从特定节点搜索,所以它没有任何区别)但我不想写坏的代码。
总而言之,我们如何决定在哪里节省用户的性能,内存和灵活性(他是否能够从任何节点搜索或创建非静态比较函数?)