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 :).
Related
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'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.
Writing a function to do a head insert on a linked-list. It's half working as in it's inserting the object into head and reattaching the list but I'm losing my original head node in the list somehow.
If list is [green, red, blue] and I try to insert yellow, it will work but the new list will be [yellow, red, blue].
Node class is:
template<class T>
class Node
{
public:
Node(T theData, Node<T>* theLink) : data(theData), link(theLink){}
Node<T>* getLink( ) const { return link; }
const T& getData( ) const { return data; }
void setData(const T& theData) { data = theData; }
void setLink(Node<T>* pointer) { link = pointer; }
private:
T data;
Node<T> *link;
};
List is stored into a queue, so the head insert is a method of that class. Queue has private variables front and back that point to the corresponding positions of the list.
template<class T>
void Queue<T>::headInsert(T& theData)
{
Node<T> *temp;
temp = front->getLink();
front->setLink(new Node<T>(theData, temp->getLink() ));
front = front->getLink();
}
Your problem is in your setLink call:
template<class T>
void Queue<T>::headInsert(T& theData)
{
Node<T> *temp;
temp = front->getLink();
front->setLink(new Node<T>(theData, temp->getLink() )); // Right here
front = front->getLink();
}
You actually have a number of problems. First off, let's suppose we have the following test list:
front = Red -> Green -> Blue -> NULL
The call temp = front->getLink() yields the following output:
temp = Green -> Blue -> NULL.
The new Node<T>(theData, temp->getLink()) call, where theData = Yellow, then yields:
new Node<T>(theData, temp->getLink()) = Yellow -> Blue -> NULL.
Calling front->setLink(new(...) then gives you:
front = Red -> Yellow -> Blue -> NULL
Lastly, front = front->getLink():
front = Yellow -> Blue -> NULL.
This is not what you want. You simply want to take yellow and pop it on the front of the list:
template<class T>
void Queue<T>::headInsert(T& theData)
{
front = new Node<T>(theData, front);
}
No need to modify internal pointers. Just point front to be the new node containing your data, with it's next pointer pointing to the old data.
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
This is an interview question that I found interesting.
Write a method that takes a pointer to a Node structure as a parameter and returns a complete copy of the passed-in data structure.
The Node structure contains two pointers to other Node structures.
For example, the method signature could look like so:
Node* Copy(Node* root);
Note - Do not make any assumptions about the data structure – it could be a tree, linked list, graph, etc.
How can this be done for any data structure ?
In the generic graph case, you need a mapping from nodes in the original graph to nodes in the new graph, so that when a cycle is encountered, the proper link gets created. If you happen to have extra temporary space in each node, large enough to hold a pointer, then you can store the mapping directly in the nodes; otherwise, you'll need to use an external map, such as an associative array or hash table.
Then it's just a matter of traversing the graph, copying nodes, and looking up the corresponding edges. Something like this:
struct Node
{
Node(int _data) : data(_data) { memset(links, 0, sizeof(links)); }
int data;
Node *links[2];
}
Node *Copy(Node *root)
{
typedef std::map<Node*, Node*> NodeMap;
NodeMap nodeMap;
std::deque<Node*> nodesToVisit;
// Set up initial new root and mapping for the root
Node *newRoot = new Node(root->data);
nodeMap[root] = newRoot;
// Breadth-first search the graph
nodesToVisit.push_back(root);
while(!nodesToVisit.empty())
{
Node *cur = nodesToVisit.front();
nodesToVisit.pop_front();
Node *newCur = nodeMap[cur];
for(int i = 0; i < 2; i++)
{
Node *link = cur->links[i];
if(link)
{
// If we've already created the corresponding node for this
// link, use that. Otherwise, create it and add it to the map.
NodeMap::iterator mappedLink = nodeMap.find(link);
if(mappedLink != nodeMap.end())
{
newCur->links[i] = mappedLink->second;
}
else
{
Node *newLink = new Node(link->data);
nodeMap[link] = newLink;
newCur->links[i] = newLink;
nodesToVisit.push_back(link);
}
}
}
}
return newRoot;
}
The problem as stated is impossible. You have to assume that the entire data structure is stored entirely within the content of nodes that are accessible from that initial one. But that is not an assumption you are allowed to make. Even your standard basic double linked list might not fit that description.
class Copier {
std::map <Node*, Node*> copies;
Node* Copy(Node* n) {
if (!n) return 0;
Node*& copy = copies[n];
if (!copy) {
copy = new Node();
copy.node1 = Copy(n.node1);
copy.node2 = Copy(n.node2);
}
return copy;
}
}
Node* Copy(Node* root) {
if (root == NULL)
return root;
std::unordered_map<Node*, Node*> completed;
std::deque<Node*> todo;
Node *ret = new Node(*scur);
completed.push_back(std::make_pair(root, ret));
todo.push_pack(root);
//while there's more nodes to duplicate
do {
//duplicate the node
Node* oldNode = todo.back();
Node* newNode = completed[cur];
todo.pop_back();
if(oldNode->left) {
auto iter = completed.find(oldNode->left);
//if it has a left child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->left = new Node(*(oldNode->left));
completed.push_back(std::make_pair(oldNode->left, newNode->left));
todo.push_back(oldNode->left);
} else {
newNode->left = completed[oldNode->left];
}
}
if(oldNode->right) {
auto iter = completed.find(oldNode->right);
//if it has a right child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->right = new Node(*(oldNode->right));
completed.push_back(std::make_pair(oldNode->right, newNode->right));
todo.push_back(oldNode->right);
} else {
newNode->right= completed[oldNode->right];
}
}
} while(todo.empty() == false)
//return the translation of the root
return ret;
}
Doesn't have stack overflow, root can be NULL, doesn't fail if left or right are NULL.
[Edit]Adam Rosenfield made me realize this was incorrect if there was loops in the network. Had to rewrite almost from scratch. Due to the large amount of code required, I prefer his code's for loop.
return new Node(*node);
Trick question?
You should write it recursively;
Node * Copy( Node * root )
{
Node * node_copy;
node_copy = new Node; // Assume Node1 and Node2 are initialized to 0
node_copy->content = root->content;
if( root->Node1 ) node_copy->Node1 = Copy( root->Node1 );
if( root->Node2 ) node_copy->Node2 = Copy( root->Node2 );
return node_copy;
}
So, this does not make any assumption on the data type
Given that a copy constructor exists that copies only the contents of a node and not its children:
Node* Copy(Node* root)
{
Node* copy = new Node(*root);
copy->left = Copy(root->left);
copy->right = Copy(root->right);
return copy;
}
In a more general sense, I would use copy-constructors that fully copy the entire data structure:
Node* Copy(Node* root)
{
return new Node(*root);
}