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, i.e. 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:
If you aren't at a leaf, push the current node onto the stack and move on to its leftmost child.
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:
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).
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.
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.
Related
I'm trying to create a generic menu class that will be used with a 4 line LCD.
I have a specific (non template) version working, but want to extend it to allow the menu to modify a variety of data types (int, float, unsigned...).
Here's the non template version that's working as expected...
/*
* ideally this design allows for defining an arbitrary menu as shown below
* example...
* root1
* sub1-1
* sub1-2
* root 2
* root 3
* sub3-1
* sub3-2
* sub3-2-1
* sub3-2-2
*
* each node in the menu can be executed, and allow for moving to the next/prev sibling or child/parent
* this flexibility requires that each node contains pointers to parent, child, and sibling nodes.
*/
class MenuNode
{
private:
char *prompt;
int value;
public:
MenuNode *parent=NULL;
MenuNode *child=NULL;
MenuNode *prevSibling=NULL;
MenuNode *nextSibling=NULL;
void SetValue(int value)
{
this->value = value;
}
int GetValue()
{
return value;
}
char *Prompt()
{
return prompt;
}
MenuNode(char *prompt, int initialValue, MenuNode *parent, MenuNode *prevSibling)
{
Serial.print(prompt);Serial.println(F(" MenuNode"));
this->prompt = prompt;
if (prevSibling != NULL)
{
this->prevSibling = prevSibling;
prevSibling->SetNextSibling(this);
this->parent = prevSibling->parent;
}
// prevSibling if provided sets the parent
if (prevSibling==NULL && parent != NULL)
{
this->parent = parent;
this->parent->SetChild(this);
}
value = initialValue;
}
void SetChild(MenuNode *child)
{
Serial.print(prompt);Serial.println(F(" SetChild"));
this->child = child;
}
void SetNextSibling(MenuNode *nextSibling)
{
Serial.print(prompt);Serial.println(F(" SetNextSibling"));
this->nextSibling = nextSibling;
}
};
Here's some test code that creates the menu structure...
// Test menu...
MenuNode r1("R1",10,NULL,NULL);
MenuNode r2("R2",20,NULL,&r1);
MenuNode r21("R21",30,&r2,NULL);
MenuNode r22("R22",40,&r2,&r21); // setting parent is optional, the parent will be set by the prev sibling parent
MenuNode r221("R221",50,&r22,NULL);
MenuNode r2211("R2211",60,&r221,NULL);
MenuNode r2212("R2212",70,NULL,&r2211);
MenuNode r3("R3",30,NULL,&r2);
This code iterates over each element printing out the structure
void PrintMenuStructure(MenuNode *node,int offset)
{
while(node != NULL)
{
for (int i=0;i<offset;i++)
Serial.print("-");
Serial.print(node->Prompt());
Serial.print(" = ");
Serial.print(node->Value());
if (node->parent != NULL)
{
Serial.print(" parent=");
Serial.print(node->parent->Prompt());
}
if (node->prevSibling != NULL)
{
Serial.print(" prevSib=");
Serial.print(node->prevSibling->Prompt());
}
if (node->nextSibling != NULL)
{
Serial.print(" nextSib=");
Serial.print(node->nextSibling->Prompt());
}
if (node->child != NULL)
{
Serial.print(" child=");
Serial.print(node->child->Prompt());
}
Serial.println();
if (node->child != NULL)
PrintMenuStructure(node->child,++offset);
node = node->nextSibling;
}
}
This is the output of the previous function demonstrating the structure of the menu...
R1 = 10 nextSib=R2
R2 = 20 prevSib=R1 nextSib=R3 child=R21
-R21 = 30 parent=R2 nextSib=R22
-R22 = 40 parent=R2 prevSib=R21 child=R221
--R221 = 50 parent=R22 child=R2211
---R2211 = 60 parent=R221 nextSib=R2212
---R2212 = 70 parent=R221 prevSib=R2211
-R3 = 30 prevSib=R2
It all works the way I want, but GetValue/SetValue only operate on int data.
I can create a template version of the class, with the data types of GetValue and SetValue defined by the template parameter, but I don't know now to iterate over the nodes once I do that.
Seems like a simple enough task, but I've been beating my head against the wall for a while, and haven't come up with anything that works. Any help pointing me in the right direction would be appreciated.
I'm trying to figure out how to iterate over a linked list of classes, but can't figure out how to get a pointer to start iterating.
Sorry, I couldn't get the code formatting to work... :(
The way I interpret your requirement: it seems your should make your
int value;
a std::variant.
That's the lowest cost path.
If you templatize the MenuNode class with its value type. Then a MenuNode<int>* cannot be the parent of a MenuNode<float*>, etc. Not without some effort. You'd probably better off make it polymorphic by derivate each type of value your want to support from a common abstract virtual base, and depend on how you want to use the value, design your interface.
For an assignment for school, I need to take a binary search tree and convert it into a double-threaded binary search tree. I have a general understanding on how the threads work, but I realize that in order to know where it exactly the threads are, I need to know the parent of the last inserted node (prev), as well as the parent of that node as well (twoBack). However, in my attempts to modify one of the functions in order to save those values, I can not quite get what I am looking for.
If someone could point out exactly what I'm doing wrong, and explain it to me so that I can learn from my mistakes, I'd greatly appreciate it. Thanks!
Both of these functions a are part of the class for the BST itself:
void insert(const Key& k, const E& e)
{
root = inserthelp(root, k, e);
nodecount++;
}
BSTNode<Key, E>* BST<Key, E>::inserthelp(BSTNode<Key, E>* root, const Key& k, const E& it)
{
if (root == NULL) // Empty tree: create node
{
return new BSTNode<Key, E>(k, it, NULL, NULL);
}
if (k < root->key())
{
if (prev != NULL)
twoBack = prev;
prev = root;
root->setLeft(inserthelp(root->left(), k, it));
}
else
{
if (prev != NULL)
twoBack = prev;
prev = root;
root->setRight(inserthelp(root->right(), k, it));
}
return root; // Return tree with node inserted
}
This question ha sbeen aswered due to the comments left.
I'm coding red-black tree using C++-smart pointers. I designed left and right child to be owned by its parent, so it is unique_ptr<Node> member variable of its parent node, and 'parent' member variable is set to be Node*, because the children clearly does not have ownership.
My problem is: A function that rotates tree takes argument as unique_ptr<Node>&, because it changes positions of node, but I need to pass a parent node to the function, which is in type of Node* that does not match with function argument type.
The solution I think:
1) Make parent() function that returns unique_ptr<Node>. This would be something that starts from the root of the tree and descend to find the pointer that match with parent's address. CONS: slow as hell
2) for node->parent, return node->parent->parent->left or right after some checks.
CONS: code gets little bit messier
3) Make another unique_ptr<Node> by giving Node* as an argument of constructor, and pass that. CONS: I'm not sure that the newly created unique_ptr object would coincide with already existing unique_ptr<Node> object.
4) Use shared_ptr<Node> for child, weak_ptr<Node> for parent instead. Then I could use node->parent.lock() as function argument.
CONS: child pointers' ownership are not meant to be 'shared'.
5) Discard all smart pointer things. Aww.
struct Node {
T data;
Node* parent = nullptr;
unique_ptr<Node> left, right;
bool color = false;
Node(const T& d) : data(d) {};
Node* grandparent() {
if (parent == nullptr) {
return nullptr;
}
return parent->parent;
}
}
/* SOMETHING... */
void rotate_right(unique_ptr<Node>& pivot) {
if (pivot->left == nullptr) {
return;
}
auto pivot_new = move(pivot->left);
auto pivot_parent = pivot->parent;
pivot->left = move(pivot_new->right);
pivot_new->right = move(pivot);
pivot->parent = pivot_new.get();
if (pivot->left != nullptr) {
pivot->left->parent = pivot.get();
}
if (pivot_parent != nullptr) {
if (pivot == pivot_parent->left) {
pivot_parent->left = move(pivot_new);
} else if (pivot == pivot_parent->right) {
pivot_parent->right = move(pivot_new);
} else {
throw invalid_argument("pivot_parent is actually not parent, why?\n");
}
}
pivot_new->parent = pivot_parent;
}
/* SOME OTHER THINGS */
void insert_repair_tree(Node* node) {
if (node->parent == nullptr) {
// this is root. paint BLACK
node->color = true;
} else if (node->parent->color) {
// parent is BLACK. tree is valid. do nothing
} else if (!get_color(node->uncle())) {
// parent is RED. uncle exists and RED. grandpa exists and BLACK.
// repaint parent and uncle to BLACK, and grandpa to RED.
// recursively repair tree at grandpa
node->parent->color = true;
node->uncle()->color = true;
node->grandparent()->color = false;
insert_repair_tree(node->grandparent());
} else {
// parent is RED. uncle is BLACK (not sure that it exists). grandpa exists and BLACK.
auto grandpa = node->grandparent();
if (node == grandpa->left->right) {
rotate_left(grandpa->left);
node = node->left.get();
} else if (node == grandpa->right->left) {
rotate_right(grandpa->right);
node = node->right.get();
}
grandpa = node->grandparent();
// PROBLEMS HERE
if (node == node->parent->left) {
rotate_right(grandpa);
} else if (node == node->parent->right) {
rotate_left(grandpa);
} else {
throw invalid_argument("");
}
node->parent->color = true;
grandpa->color = false;
}
}
I'm working on my C++ university assignment, and I have a problem with re-balancing a red-black tree after inserting a node in it. Everything works when inserting a root node, but once I insert more than the root node, the program crashes. This bug is driving me crazy and it's probably some silly mistake as I'm VERY new to C++.
It also works perfectly if I comment out the 2nd, 4th and 5th if statements in the putHelper function. I'm thinking the problem is maybe because I'm dereferencing uninitialised pointers in those if statements, but I'm not really sure, and if that is the case, how would I go about fixing it?
I'm posting relevant code snippets below, but if anyone wants to try running the code, I can post that too. It's very much a work in progress which hasn't been tested much yet (and I still need to code a remove function).
This is the header file, data.h:
http://pastebin.com/Fr1SKERV
And this is the main tester file, main.cpp:
http://pastebin.com/UxKRaG53
Here are relevant code snippets:
Node class declaration (K and V are generic variables):
class Node
{
public:
K key; // The index of the node.
V value; // The value of the node.
Node *right; // A pointer to the right subtree.
Node *left; // A pointer to the left subtree.
bool isRed; // TRUE if the node is red and FALSE if the node is black.
Node(K key, V value) // Constructor.
{
this->key = key;
this->value = value;
this->right = 0;
this->left = 0;
this->isRed = true;
}
};
Main insert function:
template<typename K, typename V> void Map<K, V>::put(K key, V value) // Function to insert a new node to the tree.
{
root = putHelper(root, key, value);
root->isRed = false;
size++;
}
Insert helper function:
template<typename K, typename V> typename Map<K, V>::Node *Map<K, V>::putHelper(Node *x, K key, V value) // Recursive helper function for put that traverses the tree and inserts a new node at the proper position, after which it balances the tree.
{
if (x == 0)
{
return new Node(key, value); // If the position for the new node was found...
}
if ((x->left->isRed) && (x->right->isRed)) // If both children nodes are red...
{
flipColour(x);
}
if (key == x->key) // If the key is already in use...
{
x->value = value; // Update the node with the new value.
}
else if (key < x->key)
{
x->left = putHelper(x->left, key, value); // Move to the left child.
}
else
{
x->right = putHelper(x->right, key, value); // Move to the right child.
}
if (x->right->isRed) // If the child node to the right of the parameter node is red...
{
x = rotateLeft(x);
}
if ((x->left->isRed) && (x->left->left->isRed)) // If the child node to the left of the parameter node and the child node to the left of that are both red...
{
x = rotateRight(x);
}
return x;
}
Red-black tree balancing functions (flip colour and rotate):
template<typename K, typename V> void Map<K, V>::flipColour(Node *x) // Function to flip the colour of a node and its two children.
{
x->isRed = !x->isRed; // Flip the colour of the parameter node.
x->left->isRed = !x->left->isRed; // Flip the colour of the left child node.
x->right->isRed = !x->right->isRed; // Flip the colour of the right child node.
}
template<typename K, typename V> typename Map<K, V>::Node *Map<K, V>::rotateLeft(Node *x) // Function to rotate a set of three nodes to the left.
{
Node *y = x->right; // Create a new node from the parameter node's right child node.
x->right = y->left;
y->left = x;
y->isRed = y->left->isRed;
y->left->isRed = true; // Set the new node's left child node to red.
return y;
}
template<typename K, typename V> typename Map<K, V>::Node *Map<K, V>::rotateRight(Node *x) // Function to rotate a set of three nodes to the right.
{
Node *y = x->left; // Create a new node from the parameter node's left child node.
x->left = y->right;
y->right = x;
y->isRed = y->right->isRed;
y->right->isRed = true; // Set the new node's right child node to red.
return y;
}
Any help would be greatly appreciated as the deadline for this assignment is approaching soon! Thanks in advance :).
There seems to be an issue with my dequeue function within a queue class that I have. My dequeue function which is part of the position class, is not returning the correct values that have been enqueued into the list.
The values that have been enqueued are which is a position object, are 2,1 and -1, but when I dequeue that object i get 2,506216, and -1; When I assign the *pos ponter to an object I am left with the default values;The enqueue function seems to be working correctly for when I check the ptr values they are correct.
//position constructor
front = back = &header;
struct Posnode
{
Position *pos;
Posnode *next;
};
class Position
private:
Posnode *front,*back,header;
void Position::dequeue(Position&p)
{
Posnode *ptr=front->next;
front->next = ptr->next;
p = *ptr->pos;
p.geta();//checking for values but am left with the default
if (back == ptr)
{
back = front;
}
delete ptr;
}
v
oid Position::enqueue(Position n) //assigning Position object to end of queue
{
Posnode *ptr = new Posnode;
ptr-> pos = &n;
back->next = ptr;
back = ptr;
return;
}
Position copy,intial(5);
copy = intial;
if (copy.ismovelegal(posmoves, r))
{
copy.makemove(posmoves, r);
if (intial.solved(copy))
{
cin.get();
}
else
{
p.enqueue(copy);
}
}
copy.free();//clearing object private memebers
}
intial.free();
p.dequeue(o);//copy that was previous enqued is not enqued
o.geta();
Just Check out the Implementation of Deque first and then try your own. If its some syntax or semantic error post minimal code that reproduces your code.
this link might help you. Deque Implementation