C ++中有序树的良好节点定义

时间:2012-09-02 00:22:25

标签: c++ data-structures api-design

我有一个有序的树,表示整数集。每个节点存储相关子树的大小,以及该子树中的max和min元素。所有节点的分支度,如果已修复(但在运行时确定)。此外,对于足够小的子树,我想将表示更改为相关子集的位图。例如,根节点可以存储一组大小为1000000的集合,其中一个子节点将存储大小为100000的子集,然后他的一个子节点将再次存储大小为10000的子集,在下一级别我们将停止使用此表示形式,只存储相关子集的普通位图。

我正在尝试用C ++实现这个结构,我对节点类型的定义存储了三个整数(size,min和max),一个指针数组(类似于node_t ** children)到子树和位图(in我们使用这种表示的情况)。问题是所有节点都存储至少一个不相关的元素(例如,如果集合足够大,我们将使用指针数组,而不是位图,例如)。如何声明节点类型来解决这个问题?我想过使用两个节点子类型(每种情况一个),但我不确定在运行时对性能的影响是什么。

提前致谢。 PS。如果问题不清楚,请告诉我。

1 个答案:

答案 0 :(得分:1)

由于您使用多个表示,您可能至少需要两种节点类型:第一种是处理根以及附近后代的通用节点,第二种类型将包含指向地图的指针。后面的节点没有任何子节点,但是它们的直接祖先应该将它们视为整个子树而不是指向地图的终止节点。

由于每个上层节点都有指向其子节点的指针,因此您需要一种方法来确保这些指针也能够指向mapNodes以及分支节点。执行此操作的一种好方法是使用虚函数创建虚拟基节点类型,该函数返回您要查找的任何数据。例如:

class baseNode {
  virtual int getLargest();
  virtual baseNode* addData(int);
};

class leafNode : baseNode { //for non-map termination
  leafNode(int in) {Data = in;}

  int getLargest() {return Data;}
  baseNode* addData(int);

  int Data;
};

class treeNode : baseNode {

public:
  int getLargest(); //returns leftChild->getLargest(), etc
  baseNode* addData(int);

  baseNode* leftChild;//can point to either a treeNode or mapNode
  baseNode* rightChild;
};

class mapNode : baseNode {
  baseNode* addData(int);
  int getLargest(); //parses subMap to find/return the desired value

  Map* subMap;
};

你需要一点时间来做它你需要的东西,但原则是一样的。请记住,对于1m对象,您添加的每个字节都会使净内存使用量增加大约1兆字节,因此请尽量减少使用量。如果所有分支节点最终都到达mapNode,则可以完全取消leafNode声明。

向结构中添加数据非常棘手,特别是因为您正在处理多种类型,并且父母(希望)对他们的邻居一无所知;使用虚拟访问器来完成所需的操作。在许多情况下,如果分支节点尝试在“向下”添加值,则它引用的子节点可能需要更改类型。在这种情况下,子进程应该构造新的子结构,然后将其返回给父进程。这可以这样做:

baseNode* treeNode::addData(int in) {
  if ((childCount+1) < threshold) { //not enough to merit a map
    //....
    //if (input needs to go to the leftChild) {
      if (leftChild == 0) {
        leftChild = new leafNode(in); 
      } else {
        leftChild = leftChild->addData(in);
      }
    //}  
    return (baseNode*)this; //casting may be optional
  } else {  //new Data merits converting self + kids into a map
    mapNode* newMap = new mapNode();
    //Set newMap->subMap to children, deleting as you go

    delete this;//remove self after return
    return (baseNode*)newMap; //return the mapNode holding subtree
  }
}

baseNode* leafNode::addData(int in) {
  treeNode* tmpNode = new treeNode(); //create replacement
  tmpNode->leftChild = this; //pin self to new node
  tmpNode->rightChild = new leafNode(in); //store data
  return (baseNode*)tmpNode;
}

baseNode* mapNode::addData(int in) {
  subMap->addValue(in);//However you do it...
  return (baseNode*)this; //parent is always a treeNode
}

leftChild = leftChild->addData(in);通常不会实际修改任何内容,特别是如果它指向treeNode,但它并没有真正伤害任何事情而且额外的if (newPtr != leftChild)检查会增加不必要的开销。请注意,如果leafNode需要更改为包含多个孩子的treeNode,或者如果是一个有足够孩子的treeNode值得将自己(并且是孩子们!)更改为mapNode,那么导致更改。< / p>

相关问题