I have a problem - I need to answer question if given 2 nodes (A, B) is A ancestor of B. I know that the possible solution is to get the time when I enter the node and the time when I leave it. Based on this I can calculate relationship fast. How to get those 'timestamps' using DFS which can not be implemented using recurrence?
I am not expert in algorithms and C++, that is why I am asking.
I found a way to get it. If Your tree in adjacency list then You can go with preprocessing. To each node You need to assign the value when You enter it and when You leave it during DFS, then in constant time You can check it:
if (timeIn[b] >= timeIn[a] && timeIn[b] <= timeOut[a]) {
printf("YES\n");
}
else {
printf("NO\n");
}
where a is possible ancestor of b.
DFS:
// INITIALIZE VARs
int time = 0;
stack<int> stackOfChildNodes;
// put root of tree
stackOfChildNodes.push(first);
// go with DFS
while (!stackOfChildNodes.empty()) {
int current = stackOfChildNodes.top();
stackOfChildNodes.pop();
// if node was not visited (time is not set)
if (timeIn[current] == -1) {
timeIn[current] = time; // node visited
time++; // increase time to go further
stackOfChildNodes.push(current); // include node in processing to leave it in future
int child = children[current];
// add descendants to process them
while (child != 0) {
stackOfChildNodes.push(child);
child = descendants[child];
}
}
// if node was visited, so we gonna leave him now
if (timeIn[current] != -1) {
timeOut[current] = time-1;
}
}
With standard augmented thread indices (ATI -- see reference provided below), that provide for node length data structures, usually arrays, answering the question of whether A is B's ancestor is not possible in constant time.
If you store the pred, thread and depth (that constitute the fundamental data structures in the ATI scheme) of each node, the question of whether A is B's ancestor can be done in O(N) time -- just retrace from B using the pred data structure until you reach the root and check if you encounter A.
However, you can do the above for each node as a preprocessing step and then have a new node length array, ancestor for each node which indicates whether another node is its ancestor or not.
Reference: Bazaara, Jarvis and Sherali page 482.
Related
I am trying implementing the huffman algorithm following the steps described in this tutorial: https://www.programiz.com/dsa/huffman-coding, and so far I got this code:
void encode(string filename) {
List<HuffmanNode> priorityQueue;
List<Node<HuffmanNode>> encodeList;
BinaryTree<HuffmanNode> toEncode;
//Map<char, string> encodeTable;
fstream input;
input.open(filename, ios_base::in);
if (input.is_open()) {
char c;
while (!input.eof()) {
input.get(c);
HuffmanNode node;
node.data = c;
node.frequency = 1;
int pos = priorityQueue.find(node);
if(pos) {
HuffmanNode value = priorityQueue.get(pos)->getData();
value++;
priorityQueue.update(pos, value);
} else {
priorityQueue.insert(node);
}
}
}
input.close();
priorityQueue.sort();
for(int i=1; i<=priorityQueue.size(); i++)
encodeList.insert( priorityQueue.get(i) );
while(encodeList.size() > 1) {
Node<HuffmanNode> * left = new Node<HuffmanNode>(encodeList.get(1)->getData());
Node<HuffmanNode> * right = new Node<HuffmanNode>(encodeList.get(2)->getData());
HuffmanNode z;
z.data = 0;
z.frequency = left->getData().frequency + right->getData().frequency;
Node<HuffmanNode> z_node;
z_node.setData(z);
z_node.setPrevious(left);
z_node.setNext(right);
encodeList.remove(1);
encodeList.remove(1);
encodeList.insert(z_node);
}
Node<HuffmanNode> node_root = encodeList.get(1)->getData();
toEncode.setRoot(&node_root);
}
full code for the main.cpp here: https://pastebin.com/Uw5g9s7j.
When I try run this, the program read the bytes from the file, group each character by frequency and order the list, but when I try generate the huffman tree, I am unable to traverse this tree, always falling into a infinte loop (the method get stuck in the nodes containing the 2 first items from the priorityQueue above).
I tried the tree class with BinaryTree<int>, and everything works fine in this case, but with the code above the issue happens. The code for the tree is this (in the code, previous == left and next == right - I am using here the same Node class already implemented for my List class): https://pastebin.com/ZKLjuBc8.
The code for the List used in this example is: https://pastebin.com/Dprh1Pfa. And the code for the Node class used for both the List and the BinaryTree classes is: https://pastebin.com/ATLvYyft. Anyone can tell me what I am missing here? What I am getting wrong here?
UPDATE
I have tried a version using only c++ stl (with no custom List or BinaryTree implementations),but the same problem happened. The code is that: https://pastebin.com/q0wrVYBB.
Too many things to mention as comments so I'm using an answer, sorry:
So going top to bottom through the code:
Why are you defining all methods outside the class? That just makes the code so much harder to read and is much more work to type.
Node::Node()
NULL is C code, use nullptr. And why not use member initialization in the class?
class Node {
private:
T data{};
Node * previous{nullptr};
Node * next{nullptr};
...
Node::Node(Node * node) {
What is that supposed to be? You create a new node, copy the value and attach it to the existing list of Nodes like a Remora.
Is this supposed to replace the old Node? Be a move constructor?
Node::Node(T data)
Write
Node<T>::Node(T data_ = T{}) : data{data_} { }
and remove the default constructor. The member initialization from (1) initializes the remaining members.
Node::Node(T data, Node * previous, Node * next)
Again creating a Remora. This is not inserting into an existing list.
T Node::getData(), void Node::setData(T value)
If everyone can get and set data then just make it public. That will also mean it will work with cons Node<T>. Your functions are not const correct because you lack all the const versions.
Same for previous and next. But those should actually do something when you set the member. The node you point to should point back to you or made to do so:
void Node::setPrevious(Node * previous) {
// don't break an existing list
assert(this->previous == nullptr);
assert(previous->next == nullptr);
this->previous = previous;
previous->next = this;
}
Think about the copy and move constructors and assignment.
Follow the rule of 0/3/5: https://en.cppreference.com/w/cpp/language/rule_of_three . This goes for Node, List, ... all the classes.
List::List()
Simpler to use
Node<T> * first{nullptr};
List::~List()
You are deleting the elements of the list front to back, each time traversing the list from front till you find index number i. While horrible inefficient the front nodes have also already been deleted. This is "use after free".
void List::insert(T data)
this->first = new Node<T>();
this->first->setData(data);
just write
first = new Node<T>(data);
And if insert will append to the tail of the list then why not keep track of the tail so the insert runs in O(1)?
void List::update(int index, T data)
If you need access to a list by index that is a clear sign that you are using the wrong data structure. Use a vector, not a list, if you need this.
void List::remove(int index)
As mentioned in comments there are 2 memory leaks here. Also aux->next->previous still points at the deleted aux likely causing "use after free" later on.
int List::size()
Nothing wrong here, that's a first. But if you need this frequently you could keep track of the size of the list in the List class.
Node * List::get(int index)
Nothing wrong except the place where you use this has already freed the nodes so this blows up. Missing the const counterpart. And again a strong indication you should be using a vector.
void List::set(int index, Node * value)
What's this supposed to do? Replace the n-th node in a list with a new node? Insert the node at a specific position? What it actually does it follow the list for index steps and then assign the local variable aux the value of value. Meaning it does absolutely nothing, slowly.
int List::find(T data)
Why return an index? Why not return a reference to the node? Also const and non-const version.
void List::sort()
This code looks like a bubblesort. Assuming it wasn't totaly broken by all the previous issues, would be O(n^4). I'm assuming the if(jMin != i) is supposed to swap the two elements in the list. Well, it's not.
I'm giving up now. This is all just the support classes to implement the BinaryTree, which itself is just support. 565 lines of code before you even start with your actual problem and it seems a lot of it broken one way or another. None of it can work with the state Node and List are in. Especially with copy construction / copy assignment of lists.
I am looking to build my own map class. (Which will behave exactly like the C++ STL) I want to be able to iterate through all the elements in order by key value.
I implemented my map as an unbalanced binary search tree.
So my question is how to do an iterator increment efficiently. One inefficient way is to iterate through every single element in the tree to find the next lowest key. Is there a faster way to do this?
Thank you.
It depends a bit on the implementation details. If the nodes of your unbalanced binary search tree have a "parent" pointer, you could use that to traverse it. Your implementation of ++iterator could look a bit like this:
if (current_node.has_right_child()) {
// We go to the right subtree of the current node and
// take the smallest element of that subtree.
current_node = current_node.right_child();
while (current_node.has_left_child()) {
current_node = current_node.left_child();
}
} else {
// We have to go up. If the current element is the left child of the parent,
// we can just go to the right child of the parent.
// If it is the right child, we have to go further up
while (true) {
if (!current_node.has_parent()) {
// We got up to the root and never found a right child.
// So we are at the end of the iteration.
current_node = NULL;
break;
}
Node* parent = current_node.parent();
bool is_left_child = parent.left_child() == current_node;
current_node = parent;
if (is_left_child) {
// if this was the left child, then the parent is the correct next element.
break;
}
// if this was the right child, we have to go further up
// until we leave this subtree, so we continue iterating.
}
}
If your binary tree does NOT have parent nodes, you could store the parents in the iterator. I.e. you could maintain a vector parents; in which you store the parents of the current node up to the root. If this is still needed, I can provide an implementation, but because you edited my "non parent pointer" version with parent pointers, it seems that you have parent pointers. So I leave it away.
I am trying to insert nodes in a list based on the value of a data member. Basically, if the member isVip evaluates to true, that node gets precedence, and should be inserted ahead of any regular node (but behind any existing VIP nodes). Regular nodes simply get added at the end of the list.
I'm pretty sure I have a good idea of how to use two pointers to step through the list and insert elements for n > 2 where n is the number of current list members, but I'm sort of conceptually stuck for the case when there's only one node.
Here is my working version of code below:
void SelfStorageList::rentLocker(Locker e) {
int count = 0;
LockerNode *p = head;
if (isEmpty()) {
head = new LockerNode(e);
tail = head;
}
for(;p!=0;count++, p=p->next) {
if(count == 1) {
if (e.isVip) {
if(p->objLocker.isVip) {
LockerNode*p = new LockerNode(e, p->next);
}
}
}
}
As you can see, I'm checking to see if the passed in object is VIP, and then whether the current one is. Here, I've hit some trouble. Assuming both are VIP, will this line:
LockerNode*p = new LockerNode(e, p->next);
put the passed in locker object in the correct place (i.e. after the current VIP one). If so, would:
LockerNode*p = new LockerNode(e, p);
equivalently place it before? Is the use or absence of the 'next' member of the node what defines the placement location, or is it something entirely different?
Hope someone can clear my doubts, and sorry if it seem a foolish question! Thanks!
Simply iterate over the list while the next node have isVip set (current->next->isVip). After the iteration, the last node visited will be the last with isVip set, and you should insert the new node after that one.
It can be implemented in fewer lines, without the explicit isEmpty check, and without any counter. Even less than that if you use a standard container instead.
I have a rooted ordered tree representing sets of integers. Each node stores the size of the associated subtree, and also the max and min elements in this subtree. The branch degree of all the nodes if fixed (but determined at runtime). Also for sufficiently small subtrees I would like to change the representation to a bitmap for the subset associated. For example the root node may store a set of size 1000000, one of this children would store a subset of size 100000, then again one of his children would store a subset of size 10000 and in the next level we would stop using this representation and store just a plain bitmap for the associated subset.
I'm trying to implement this structure in C++ and my definition for the node type stores three integers (size, min and max), an array of pointers (something like node_t ** children) to subtrees and the bitmap (in case we are using this representation). The problem is that all the nodes are storing at least one element which is irrelevant (if the set is big enough we would be using the array of pointers but not the bitmap, for example). How should the node type be declared to solve this problem ? I thought about using two subtypes of node (one for each case) but I am not sure what the impact on the performance at runtime would be.
Thanks in advance.
PS. Please let me know if the question is unclear to edit it.
Since you're using multiple representations, you'll probably need at least two node types: The first will be a generic node that handles the root as well as nearby descendants, and the second type will contain a pointer to a map. The latter nodes don't have any children persay, but their immediate ancestors should see them as an entire sub-tree rather than a terminating node that points to a map.
Since each of the upper nodes have pointers to their children, you'll need a way to ensure that these pointers are also able to point to the mapNodes as well as the branching ones. A good way to do this is to create a virtual base node type with a virtual function that returns whatever data you're looking for. For example:
class baseNode {
virtual int getLargest();
virtual baseNode* addData(int);
};
class leafNode : baseNode { //for non-map termination
leafNode(int in) {Data = in;}
int getLargest() {return Data;}
baseNode* addData(int);
int Data;
};
class treeNode : baseNode {
public:
int getLargest(); //returns leftChild->getLargest(), etc
baseNode* addData(int);
baseNode* leftChild;//can point to either a treeNode or mapNode
baseNode* rightChild;
};
class mapNode : baseNode {
baseNode* addData(int);
int getLargest(); //parses subMap to find/return the desired value
Map* subMap;
};
You'll need a bit of finessing to get it to do what you need it to, but the principle is the same. Keep in mind that with 1m objects, every byte you add increases the net memory use by about a megabyte, so do try to keep things minimal. If all of your branching nodes eventually reach a mapNode, you can eliminate the leafNode declaration altogether.
Adding data to the structure is tricky, especially since you're working with multiple types and the parents (hopefully) don't know anything about their neighbors; Use virtual accessors to do what's needed. In many scenarios, if a branching node tries to add a value 'down the line', the child node it references may need to change type. In this case, the child should construct the new substructure then return it to the parent. This can be done like so:
baseNode* treeNode::addData(int in) {
if ((childCount+1) < threshold) { //not enough to merit a map
//....
//if (input needs to go to the leftChild) {
if (leftChild == 0) {
leftChild = new leafNode(in);
} else {
leftChild = leftChild->addData(in);
}
//}
return (baseNode*)this; //casting may be optional
} else { //new Data merits converting self + kids into a map
mapNode* newMap = new mapNode();
//Set newMap->subMap to children, deleting as you go
delete this;//remove self after return
return (baseNode*)newMap; //return the mapNode holding subtree
}
}
baseNode* leafNode::addData(int in) {
treeNode* tmpNode = new treeNode(); //create replacement
tmpNode->leftChild = this; //pin self to new node
tmpNode->rightChild = new leafNode(in); //store data
return (baseNode*)tmpNode;
}
baseNode* mapNode::addData(int in) {
subMap->addValue(in);//However you do it...
return (baseNode*)this; //parent is always a treeNode
}
The leftChild = leftChild->addData(in); usually won't actually modify anything, especially if it points to a treeNode, however it doesn't really hurt anything to do so and the extra if (newPtr != leftChild) check would just add unnecessary overhead. Note that it will cause a change if a leafNode needs to change into a treeNode with multiple kids, or if it's a treeNode with enough children to merit changing itself (and it's kids!) into a mapNode.
I am working on a binary search tree in C++ at the moment and I have reached the stage where I have to write the remove/delete function(using recursive approach, x = change(x)). I have two options:
to stop at the parent of the node of the node to be deleted;
to get to the node to delete and then call a function that will
return the parent
Approach 1: less expensive, more code
Approach 2: less code, more expensive
Which approach is better according to you, and why?
I disagree that those are your only two options.
I think a simpler solutions is to ask each node weather it should be deleted. If it decides yes then it is deleted and returns the new node that should replace it. If it decides no then it returns itself.
// pseudo code.
deleteNode(Node* node, int value)
{
if (node == NULL) return node;
if (node->value == value)
{
// This is the node I want to delete.
// So delete it and return the value of the node I want to replace it with.
// Which may involve some shifting of things around.
return doDelete(node);
}
else if (value < node->value)
{
// Not node. But try deleting the node on the left.
// whatever happens a value will be returned that
// is assigned to left and the tree will be correct.
node->left = deleteNode(node->left, value);
}
else
{
// Not node. But try deleting the node on the right.
// whatever happens a value will be returned that
// is assigned to right and the tree will be correct.
node->right = deleteNode(node->right, value);
}
// since this node is not being deleted return it.
// so it can be assigned back into the correct place.
return node;
}
The best approach would be to traverse upto the parent of the node to be deleted, and then delete that child node. Eventually using this approach you always visit the child node, since you always have to confirm the child node is the node u want to delete.
I find that the most efficient form for writing functions for tree data structures in general is the following psuedocode format.
function someActionOnTree() {
return someActionOnTree(root)
}
function someActionOnTree (Node current) {
if (current is null) {
return null
}
if (current is not the node I seek) {
//logic for picking the next node to move to
next node = ...
next node = someActionOnTree(next node)
}
else {
// do whatever you need to do with current
// i.e. give it a child, delete its memory, etc
current = ...
}
return current;
}
This recursive function recurses over the vertex set of a data structure. For every iteration of the algorithm, it either looks for a node to recurse the function on, and overwrites the data structure's reference to that node with the value of the algorithm's iteration on that node. Otherwise, it overwrites the node's value (and possibly perform a different set of logic). Finally, the function returns a reference to the parameter node, which is essential for the overwriting step.
This is a generally the most efficient form of code I've found for tree data structures in C++. The concepts apply other structures as well - you can use recursion of this form, where the return value is always a reference to a fixed point in the planar representation of your data structure (basically, always return whatever is supposed to be at the spot you're looking at).
Here's an application of this style to a binary search tree delete function to embellish my point.
function deleteNodeFromTreeWithValue( value ) {
return deleteNodeFromTree(root, value)
}
function deleteNodeFromTree(Node current, value) {
if (current is null) return null
if (current does not represent value) {
if (current is greater than my value) {
leftNode = deleteNodeFromTree(leftNode, value)
} else {
rightNode = deleteNodeFromTree(rightNode, value)
}
}
else {
free current's memory
current = null
}
return current
}
Obviously, there are many other ways to write this code, but from my experience, this has turned out to be the most effective method. Note that performance isn't really hit by overwriting pointers, since the hardware already cached the nodes. If you're looking into improving performance of your search tree, I'd recommend looking into specialized trees, like self-balancing ones (AVL trees), B-trees, red-black trees, etc.