我想制作一棵树,每个节点都可以有一些孩子,但我不知道它们的数量。树必须使用(无额外数据)在每个节点上以恒定时间编码在小内存中。我认为我将使用value和children属性(value为int,children为stack)创建类Tree,并指向该Tree中每个节点的指针数组。我的问题是制作这个数组。如何在没有额外数据的情况下创建它(std::vector
有时会分配比所需更多的内存)和每个单元的恒定时间?
一切都很好,但我还需要每个节点都有不间断的时间。我知道会有多少节点,但我不知道如何制作每个节点的数组。它应该工作类似于:
array[n];
要么:
*(数组+ 1)= N;
A_Node *array[0]= new A_Node(16);
A_Node *n = new A_Node(1);
array[0]->addChild(n);
array[1]=n;
答案 0 :(得分:2)
这是一个可能的例子。它不是一个完整的示例解决方案,但我希望你明白这一点。关键是你可以有一个指向节点的双指针,它基本上是一个指向树节点的指针数组。
然后,您可以自己重新分配大小,无论何时需要,都可以重新分配大小。但是std :: vector已经为你做了这个,所以没有真正的理由不使用它,除非你想自己控制一切或者实验,或者用C写一些东西。无论如何希望这会有所帮助。
#include <stdio.h>
#include <stdlib.h>
// The initial buffer length of a node's children
#define BUFFER_LENGTH 5
// How much to multiply with if an addition of a child goes over the buffer
#define MULTIPLIER 2
///Your node class
class A_Node
{
public:
A_Node(int value,unsigned int childrenN=0)
{
this->value = value;
this->childrenN = childrenN;
//allocate BUFFER_LENGTH children for the node at first or childrenN if the childrenN is not initially 0
if(childrenN != 0)
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*childrenN);
this->bufferLength = childrenN;
}
else
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*BUFFER_LENGTH);
this->bufferLength =BUFFER_LENGTH;
}
}
//in the destructor of a node it would need some special care
~A_Node()
{
//for every child call the destructor of each child
for(int i = 0; i < this->childrenN; i++)
{
delete this->children[i];
}
//and only then free the buffer of the pointers to the children
free(this->children);
}
//adds a child
void addChild(A_Node* child)
{
//reallocate if needed
if(childrenN >= this->bufferLength)
{
realloc(this->children,sizeof(A_Node*)*MULTIPLIER);
}
this->children[childrenN] = child;
this->childrenN++;
}
A_Node* getChild(unsigned int i)
{
if(i >= this->childrenN)
{
return 0;
}
return this->children[i];
}
void printValue()
{
printf("%d\n",this->value);
}
private:
int value;
unsigned int childrenN;
A_Node** children;
unsigned int bufferLength;
};
///Your tree class
class A_Tree
{
public:
//constructor
A_Tree(int rootValue)
{
root = new A_Node(rootValue);
}
//destructor
~A_Tree()
{
//recursively kills all the nodes due to the destructor of node
delete root;
}
//your root node
A_Node* root;
};
int main()
{
A_Tree tree(16);
tree.root->addChild(new A_Node(42));
tree.root->printValue();
(tree.root->getChild(0))->printValue();
return 0;
}
答案 1 :(得分:1)
只需自己跟踪记忆而不是使用矢量:
class Node {
public:
// In the constructor, initialize your array of children to NULL
// and the size of your children array to zero
Node() : mChildren(NULL), mSize(0) {}
void AddChild(Node* newChild) {
// allocate space for your new array
Node** newArray = new Node*[mSize + 1];
// copy over nodes from old array to new array
for (int i = 0; i < mSize; i++) {
newArray[i] = mChildren[i];
}
// add in our new child to the end of the array
newArray[mSize++] = newChild;
// if there was an old array (null check) free the memory
if (mChildren) {
delete [] mChildren;
}
// set our children array equal to our new array
mChildren = newArray;
}
Node* AccessChild(size_t index) {
// make sure it's a valid index and then return
assert(index < mSize);
return mChildren[index];
}
private:
Node** mChildren;
int mSize;
};
这对额外节点没有额外的空间,但它需要int的大小才能跟踪您存储的节点数。如果没有这个或者有一定数量的孩子,我没有任何办法可以做到这一点。
请注意,每次需要重新分配时,矢量大小加倍,因为这样效率更高。虽然上面的解决方案在内存方面会更有效,但它会损害很多性能,因为它需要为每个子节点添加一个分配,这将需要O(N)分配来添加N个节点。
向量的性能将是添加N个节点的O(log(N))分配,但是这个解决方案听起来似乎具有您正在寻找的内存效率。