Двоичное дерево: итеративная печать по порядку

Я написал реализацию Red-Black Tree со встроенным обходом по порядку (используя вложенный class Iterator).

Я ищу (итеративный, если это возможно) алгоритм, который печатает двоичное дерево графически с использованием обхода по порядку.

Ориентация печати не имеет значения, то есть дерево в выводе командной строки может быть ориентировано (отформатировано) следующим образом:

    2
/ \
1   4
/ \
3   5

или вот так:

 |1
|
|
2
| |3
| |
|4
|
|5

или даже вверх ногами, но дерево должно быть напечатано с использованием обхода in-oder, используя методы, представленные ниже:

void Iteraor::first(); // Traverses to the first node.
void Iterator::next(); // Traverses to the next node.
void Iterator::last(); // Traverses to the last node.

так что можно так сделать что-то вроде этого:

RBTree tree;
/* Tree init. */
Iterator from(&tree), until(&tree);
from.first();
until.last();
for (Iterator i = from; i != until; i.next()) {
// PRINTING.
}

Это оригинальный код:

/** A program for Red-Black Tree manipulation: insertion and value retrieval.
* All position relations (first, last, previous, next) are in-order.
*/

class RBTree {
struct Node {
enum class Colour : bool { RED, BLACK };
int value;
Node *left, *right, *parent;
Colour colour;
public:
/* ... */
};
class Iterator {
class Stack {
/* ... */
};
Stack stack;
const RBTree* const tree; // Once set, neither the reference nor the referenced object's attributes can be modified.
Node* pointer;
public:
Iterator(const RBTree*);
void first();
void next();
void last();
/* ... */
Node* getNode() const;
bool operator != (const Iterator&) const;
};
Node *root;
Iterator iterator;
public:
RBTree() : root(nullptr), iterator(this) {}
/* ... */
bool printTree() const;
~RBTree() { deleteTree(); }
};

// TREE // public: //

/* ... */

bool RBTree::printTree() const {
if (root != nullptr) {
// print ??
return true;
}
else
return false;

}

// NODE: Ensures the proper connection. //

void RBTree::Node::setLeft(Node *p_left) {
left = p_left;
if (p_left != nullptr)
p_left->parent = this;
}

void RBTree::Node::setRight(Node *p_right) {
right = p_right;
if (p_right != nullptr)
p_right->parent = this;
}

// ITERATOR //

RBTree::Iterator::Iterator(const RBTree* p_tree) : tree(p_tree), pointer(p_tree->root) {}

// Traverses to the first node (leftmost).
void RBTree::Iterator::first() {
if (pointer != nullptr) {
while (true) {
if (pointer != nullptr) {
stack.push(pointer);
pointer = pointer->left;
}
else {
pointer = stack.peek();
break;
}
}
}
}

// Traverses to next node in-order.
void RBTree::Iterator::next() {
if (pointer != nullptr) {
if (!stack.isEmpty()) {
pointer = stack.pop();
if (pointer->right != nullptr) {
pointer = pointer->right;
first();
}
}
}
}

// Traverses to the last node (rightmost).
void RBTree::Iterator::last() {
pointer = tree->root;
if (pointer != nullptr)
while (pointer->right != nullptr)
pointer = pointer->right;
stack.clear();
}

/* ... */

RBTree::Node* RBTree::Iterator::getNode() const {
return pointer;
}

bool RBTree::Iterator::operator != (const Iterator& p_iterator) const {
return pointer != p_iterator.pointer ? true : false;
}

я имею изучал ответы на аналогичный вопрос, но ни один из алгоритмов не использует обход по порядку (и большинство из них являются рекурсивными).

РЕДАКТИРОВАТЬ:

Следуя совету @ nonsensickle, код сокращен до минимума.

3

Решение

Канонический метод обхода по порядку с использованием итеративного алгоритма заключается в поддержании стека (или очереди LIFO) узлов, которые необходимо распечатать. Каждая итерация цикла выполняет одно из двух:

  1. Если у вас нет листа, поместите текущий узел в стек и перейдите к его крайнему левому дочернему элементу.

  2. Если вы находитесь на листе, распечатайте его, вытяните верхний узел из стека, распечатайте его и перейдите к его крайнему правому потомку.

Вы продолжаете до тех пор, пока ваш стек не опустеет и вы не достигнете листа.

Форматирование и генерация графического представления ветвей междоузлия, очевидно, зависит от вас. Имейте в виду, что для этого потребуются дополнительные переменные состояния.

РЕДАКТИРОВАТЬ

Что я имею в виду под «некоторыми дополнительными переменными состояния», так это.

Чтобы обеспечить красивую печать, вам нужно отслеживать три вещи:

  1. На каком уровне дерева находится ваш текущий узел для печати (считая снизу). Это говорит вам (частично) о том, как далеко он отступает (или смещается от края холста, если вы используете библиотеку 2D-рисования).

  2. Является ли ваш текущий узел для печати левым или правым потомком. Это говорит вам (опять же), как далеко отступать от его родного брата, а также ориентация ветви, соединяющей его с его родителем.

  3. Сколько узлов от «центра» вашего узла. Это также будет полезно для правильного расстояния от его (не родных) соседей.

Может быть возможно обойтись с меньшим состоянием от итерации к итерации, но это работает для меня.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]