Использование std :: unique_ptr для детей - это быстрое и грязное решение, но оно не соответствует требованию вопроса.Помещать указатели в вектор - плохая идея из-за сложного кода и сложности времени.
Быстрое и грязное решение - написать функцию в дереве, которая будет рекурсивно удалять узлы.Недостатком является потенциальное переполнение стека, если дерево не сбалансировано (как и в случае с std::unique_ptr
для дочерних элементов).Существует несколько способов борьбы с потенциальным переполнением стека:
Эффективное решение, которое не имеет переполнения стека и не может исключить std::bad_alloc
.Это алгоритм DFS, использующий в качестве стека освобожденные узлы дерева.Запись Node :: left будет указывать на полезную нагрузку (поддерево, которое нужно освободить), а Node :: right будет играть роль next
в стеке DFS (связанный список).
static Node * & nextNode(Node & node)
{ return node.right_child; }
static Node * & payload(Node & node)
{ return node.left_child; }
Tree::~Tree()
{
Node temp;
Node *stack = & temp;
payload(*stack) = root;
nextNode(*stack) = nullptr;
constexpr bool TRACE = false;
while (stack) {
Node * treeNode = payload(*stack);
Node * toPush1 = treeNode->left_child;
Node * toPush2 = treeNode->right_child;
if (toPush1) {
payload(*stack) = toPush1;
if (toPush2) {
payload(*treeNode) = toPush2;
nextNode(*treeNode) = stack;
stack = treeNode;
} else {
if (TRACE) std::cout << treeNode->data_ << " ";
delete treeNode;
}
}
else if (toPush2) {
payload(*stack) = toPush2;
if (TRACE) std::cout << treeNode->data_ << " ";
delete treeNode;
}
else { // nothing to push
Node *nextStack = nextNode(*stack);
if (TRACE) std::cout << treeNode->data_ << " ";
delete treeNode;
if (stack != &temp) {
if (TRACE) std::cout << stack->data_ << " ";
delete stack;
}
stack = nextStack;
}
}
// free the stack.
while (stack) {
Node *nextStack = nextNode(*stack);
if (stack != &temp) {
if (TRACE) std::cout << stack->data_ << " ";
delete stack;
}
stack = nextStack;
}
if (TRACE) std::cout << '\n';
}
Это позволит вам эффективно использовать память, с O (1) дополнительной памятью, и экономить время, с O (N) сложностью по времени.
Для полноты, вот остаток класса Tree:
class Tree
{
public:
Tree(int data = 0) {
root = new Node(data);
}
~Tree();
Copy ctor, assignment, move ctor, move assignment
void add(int data) {
Node *index = root;
while (true) {
if (data == index->data_) {
std::stringstream ss;
ss << data << " already exists\n";
throw std::invalid_argument(ss.str());
}
if (data < index->data_) {
if (index->left_child != nullptr) {
index = index->left_child;
continue;
}
std::unique_ptr<Node> temp = std::make_unique<Node>(data);
index->left_child = temp.release();
return;
}
if (index->right_child != nullptr) {
index = index->right_child;
continue;
}
std::unique_ptr<Node> temp = std::make_unique<Node>(data);
index->right_child = temp.release();
return;
}
}
private:
// owning the root and all descendants recursively
Node* root;
};