简体   繁体   中英

Binary Tree: iterative inorder print

I've written a Red-Black Tree implementation, with built-in in-order traversal (using nested class Iterator ).

I am looking for an (iterative, if possible) algorithm that prints the binary tree graphically using in-order traversal.

Printing orientation isn't relevant, ie the tree in the command-line output can be oriented (formatted) like this:

    2
   / \
  1   4
     / \
    3   5

or like this:

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

or even upside-down, but the tree should be printed using in-oder traversal, using methods provided below:

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

so it's possible so make something like this:

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

This is the original code:

/** 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;
}

I have studied the responses at a similar question , but none of the algorithms utilizes the in-order traversal (and most of them are recursive).

EDIT:

Folowing @nonsensickle's advice, the code is clipped down to bare minimum.

The canonical method for in-order traversal using an iterative algorithm is to maintain a stack (or LIFO queue) of the nodes you need to print. Each loop iteration does one of two things:

  1. If you aren't at a leaf, push the current node onto the stack and move on to its leftmost child.

  2. If you are at a leaf, print it, pop the top node off of the stack, print that, and move on to its rightmost child.

You continue until your stack is empty and you're at a leaf.

The formatting, and the generation of the graphical representation of the internode branches, are obviously up to you. Keep in mind that it will require some extra state variables.

EDIT

What I mean by "some extra state variables" is this.

To provide for pretty-printing, you need to keep track of three things:

  1. What level of the tree your current node-to-print is on (counting from the bottom). This tells you (part of) how far to indent it (or offset it from the edge of your canvas, if you're using a 2D drawing library).

  2. Whether your current node-to-print is a left- or right-child. This tells you (again) how far to indent it from its sibling, and also the orientation of the branch connecting it with its parent.

  3. How many nodes away from "center" your node is. This will also be useful for proper spacing from its (non-sibling) neighbors.

It may be possible to make do with less iteration-to-iteration state, but this works for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM