I'm getting an error "AddressSanitizer .. stackoverflow in operator new (unsigned long)" using this version of the code, where I use copy->neighbors.push_back
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
unordered_map<Node*, Node*> copies;
Node* cloneGraph(Node* node) {
if(!node) return node;
if(copies.find(node)==copies.end()){
Node *copy = new Node(node->val,{});
for(auto neighbor:node->neighbors){
copy->neighbors.push_back(cloneGraph(neighbor));//stackoverflow
}
copies[node]= copy;
}
return copies[node];
}
but it works with this version where I use copies[node]->neighbors.push_back , why is this happening?
the only difference is using a reference to an element of global map: copies[node] vs a local pointer copy
Node* cloneGraph(Node* node) {
if(!node) return node;
if(copies.find(node)==copies.end()){
copies[node] = new Node(node->val,{});
for(auto neighbor:node->neighbors){
copies[node]->neighbors.push_back(cloneGraph(neighbor));
}
}
return copies[node];
}
In your first implementation, you are creating a new Node each recursive call which is pushed to the stack. Whereas, in your second implementation it is being placed in an array which not part of the local recursion variables(it looks like a global variable), so the stack does not need to keep track of the newly created nodes.
When a recursive function causes a stack overflow, one of the first things you should look for is infinite recursion.
Consider a simple graph with two nodes: A is a neighbor of B, and B is a neighbor of A (pretty standard for non-directed graphs). What happens when you call cloneGraph(&A)?
Node A is not in the map, so a clone is made.
As part of the cloning process, cloneGraph(&B) is called.
So what happens next?
Node B is not in the map, so a clone is made.
As part of the cloning process, cloneGraph(&A) is called.
OK, back to where we started. This could get ugly if the recursion continues. So the big question is
At this point, is A in the map?
Using the first version of the code, it is not. So the recursion repeats until the stack overflows. Using the second version of the code, it is, so the recursion ends at this point.
In the first version you have a recursion that can produce an infinite loop for a graph with cycles. Note how the condition for entering to a deeper level of the recursion is that a node is not found in the map copies, but this map is only updated after the whole recursion finishes.
If your graph is A->B and B->A, then a call to cloneGraph(&A) will call cloneGraph(&B), and this will call cloneGraph(&A) and so on indefinitely until the call stack doesn't have space for any more.
Think carefully about your algorithm. Presumably your graph has cylces.
As your first version only adds the newly created node to copies after recursing into cloneGraph the next call will try to clone the same node again, which will recurse etc.
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 have been working with this C++ program for a while, and I have figured what exactly is happening, but I haven't figured out how to fix it exactly. Here is what I have set up:
struct entry {
string foo;
string bar;
string num;
};
struct node {
entry input;
node* left;
node* right;
};
node* home = new node;
This code takes place in a separate header file that is included in a main cpp file, which has the following:
home->input.foo="John";
home->input.bar="Doe";
home->input.name="1234";
printAll(home);
This is were the error pops up, trying to pass home through the function printAll in the header file:
void printAll(node* start){
if(start==NULL) return;
printAll(start->left);
cout << start->input.foo;
printall(start->right);
}
The error that Visual Studio gives me is 0xCDCDCDCD on start. I understand it's not home that is causing the issue, it's start, but I don't understand how to correct this error. I read around and I can assume that start has been thrown into heap memory but it is unintalized. I didn't think this was possible. And I also can guess that C++ doesn't know what start is and how to use it, how would I correct this?
You haven't initialized left or right. In debug builds, Visual Studio will set uninitialized memory to 0xCDCDCDCD. This is obviously not equal to NULL, so your comparison returns false.
As noted in the other answer, the error you are getting may be because you haven't initialized the left and right node as NULL. However you have another error and that is you have created an infinite loop in your printAll.
Your printAll function will first move to the left-most node and print it. After that it will move one node to the right, and, before prints it anything, it'll move to the left again.
The proper way of printing all the nodes is to put list of nodes within a class that keeps track of the first and last node.
Class LList {
node * startNode;
void printAll(){
if (startNode == NULL)
return;
node * currNode = startNode;
// print all the nodes moving left to right
_printAll(currNode);
}
void _printAll(currNode){
// print currNode and recursively go to next by calling
// _printAll(currNode->right)
}
}
Additional things to note
Of course, you'll want to make printAll public and the rest of the
above private.
You'll also need a function to add a node to the list. Look up linked lists attributes and methods to see what else you'll need.
It's better to avoid structs and use objects in place of them
I am trying to reverse a linked list using recursion. I made the reverse() function to reverse the list. I created a linked list in main() and also defined print() method.
I don't know what mistake I am making. Please help me correct it. The code snippets are given below.
struct node
{
int data;
struct node *next;
}*head;
void reverse(node **firstnode,node *n)
{
if(n==NULL)
{
head=n;
return;
}
reverse(&head,n->next);
struct node *q=n->next;
n->next=q;
q->next=NULL;
}
void main()
{
......
head=first;
reverse(&first,first);
print(head);
}
It may not address your question directly. However, you mentioned C++11 in the tags. So, take look at std::forward_list. It is a standard container that is based on single linked-list.
List* recur_rlist(List* head)
{
List* result;
if(!(head && head->next))
return head;
result = recur_rlist(head->next);
head->next->next = head;
head->next = NULL;
return result;
}
void printList(List* head)
{
while(head != NULL) {
std::cout<<head->data<<" ";
head = head->next;
}
}
void main()
{
List* list = createNode(2);
append(list, createNode(3));
append(list, createNode(4));
append(list, createNode(5));
append(list, createNode(6));
List* revlist = recur_rlist(list);
printList(revlist);
}
I think you mixed up your addressing at the end of the reverse function, it should probably look like:
q->next=n;
n->next=NULL;
Also, I am not sure if you need the "firstnode" argument.
Since you want to understand the code, and you have several great resources with finished code already, more finished code examples aren't needed. I'll just answer with some concepts and point you at the errors you need to fix.
First, some background concepts.
Linked lists: first and rest
Any linked list is either empty, or can be broken down into first (a node) and rest (a smaller linked list, or empty). This makes recursion much easier.
if (head){
node * first = head;
node * rest = head->next;
}
Invariant (simplified): A guarantee that is always true at the start and end of your function.
In a linked list, you expect that head points to a node, which points to another node, and so forth, until you get to the end, which is signaled by a nullptr. All of the nodes are different. All of the nodes are valid. These are the guarantees that must be true before you call your function and when your function returns.
In a recursive function, the invariants must hold on the sublist you are reversing at every step, because you return from the function at every step. But this makes recursion much easier because all you have to do is make sure that if the input is good, then your function will return a good value at the current step.
End of recursion:
You can prove that your recursive function never gets in an infinite loop by combining the previous concepts. If the invariants hold, then each step will work, and because each recursive call will take rest, which is guaranteed to be either nullptr or a shorter list, eventually we have to reach the end. And of course show that you handle the end.
Okay, on to the actual problems:
You don't handle end of recursion correctly. You just set head=nullptr at the end, and I'm pretty sure that's not what you want for head. You may want to handle the end if (nullptr == n->next), because then you know that is the last node. Of course, you still have to correctly handle the trivial case where nullptr==head.
You don't preserve invariants. You tried, but it looks like your bookkeeping is just all wrong. I suggest using the debugger or 3x5 notecards to step through what you're actually doing to fix the actual work of swapping things around. For example, it looks like you just confused which node is which in this code snippet:
struct node *q=n->next; // n is first, q is rest
// what if nullptr == q?
n->next=q; // n->next = n->next doesn't actually change anything
q->next=NULL; // this must already be true if reverse(rest) did its job
// q and n were swapped?
Also, your function takes "firstnode" but does not use it, but instead sets the global variable "head" as a side effect.
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 need a function to return a tree built from an expression say AB*B+. Each node is of type struct
struct Node {
std::string name;
Node* left;
Node* right;
}
I need to now parse the expression AB*B+. I have a stack out of std::vector<Node*>.
1) Create Node for A, push it on to stack
2) Create Node for B, push it on to stack
3) Create Node for *, pop B, assign it to right, pop A, assign it to left. Push * on to the stack
This goes on until the expression is completed.
Now if I have access to the root of the tree, I should be able to access every node. However, since I allocate all of them on the stack of the function, I am guessing when I return the root Node, though the node may be copied to RHS, the children it points to are invalid.
Should I store all the nodes on a different std::vector<Node> nodes the moment it is created. Use the stack to create parent child relationship, then return nodes by value? Does this work?
Or should I use std::shared_ptr instead for this? If so, can you given an example of how to do it?
By copy, I am guessing you mean this :
Node* root = Null;
root = nodeStack.pop();
I you really are following your algorithm perfectly , and you mean copy as the above. It should work. Definitely. May be there is something wrong with the algorithm implementation.