Linked-list in c++ - c++

I have a problem w ith linked lists in c++.
I have class looking like that:
class list {
private: struct node {
node * next;
int val;
};
node * head;
node * current;
public: list();
list(const list & l);
list & operator = (const list & l);~list();
void insert(int a);
void goToHead();
int getCurrentData();
void advance();
bool moreData();
};
I wont describe all functions in here, i'm sure they are working properly however there is declaration of operator = :
list & list::operator = (const list & l) {
if ( & l == this) return *this;
current = NULL;
node * src, * * dst;
head = ( * this).head;
src = l.head;
dst = & head;
while (src) {
if (!( * dst)) { * dst = new node;
}
( * dst) - > val = src - > val;
if (src == l.current) current = * dst;
src = src - > next;
dst = & (( * dst) - > next);
}
while (( * dst) != NULL) {
node * t = ( * dst) - > next;
delete * dst;
( * dst) = t;
}
return *this;
}
It has to copy values from one list to the other, add nodes or delete them if necessary.It works if lists are equal or if second one is longer( so it has to delete nodes).However when it should add some nodes then :
==4582== Conditional jump or move depends on uninitialised value(s)
==4582== at 0x8048C52: list::operator=(list const&) (list.cpp:103)
==4582== by 0x804891B: main (testlist.cpp:38)
==4582== Uninitialised value was created by a heap allocation
==4582== at 0x402B9B4: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4582== by 0x8048BDE: list::operator=(list const&) (list.cpp:93)
==4582== by 0x804891B: main (testlist.cpp:38)
I have no idea what is wrong with this declaration.Thanks for help.
Sorry if format was wrong, I'm having some chrome issues and that was the reason. Maybe there are examples however I have to use this one, I had a task to do it this way, I mean I had code example and just had to finish it. I still have same problem :
line 93 is :
* dst = new node;
And 103 is just last closing bracket
}
Again thanks for help.

Please format your code and mark line 93 and 103
If line 93 is
*dst=new node;
and 103
node *t=(*dst)->next;
you may want to sent dst->next to NULL (after you make the new) otherwise it points to uninitialized memory.

Related

How to iterate over a template class?

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.

c++ linked list, removing element disconnects the rest of the list

I was trying to implement this simple linked list project for my homework. When I tried to implement the removeByKey function, I ran into the problem that it disconnects the rest of the list entirely when it finds the key to be removed.
Here's the class:
class LancElem
{
private:
int key;
LancElem* next;
public:
LancElem(){next = nullptr;}
LancElem(int keyy, LancElem* nextt){key = keyy;next = nextt;}
LancElem* getNext(){return next;}
int getKey(){return key;}
void setNext(LancElem* nextt){next = nextt; }
void setKey(int keyy){key = keyy;}
};
The remove fucntion:
void removeByKey(LancElem& head, int key){
LancElem* n = head.getNext();
while(n->getNext()!=nullptr){
if(n->getNext()->getKey()==key){
n->setNext(n->getNext()->getNext());
delete n->getNext();
break;
}
n=n->getNext();
}
}
When I try to remove the biggest element:
The original linked list: 4 1 9 8 2 7 3 6 3
Expected output: 4 1 8 2 7 3 6 3
The real output: 4 1 0
The problem is probably where I connect the current element to the next->next element but I can't figure out why my implementation isn't good.
Ask yourself:
What is n->next after the line n->setNext(n->getNext()->getNext()); ? What does the line delete n->getNext(); delete?
You don't want to delete the just updated next but you want to delete the to be removed element:
auto to_be_deleted = n->getNext();
n->setNext(to_be_deleted->getNext());
delete to_be_deleted;
It seems your list has a dummy head node that does not have a value.
The function removeByKey can invoke undefined behavior when head.getNext() returns a null pointer due to using the expression n->getNext()
LancElem* n = head.getNext();
while(n->getNext()!=nullptr){
Also within the if statement
if(n->getNext()->getKey()==key){
n->setNext(n->getNext()->getNext());
delete n->getNext();
break;
}
you are trying to delete a node after the node to be deleted due to preceding assignment of the data member next by using the function setNext.
n->setNext(n->getNext()->getNext());
delete n->getNext();
Pay attention to that your function is unable to delete the node after the dummy head node due to using by you two times the call of getNext()
LancElem* n = head.getNext(); // the first call of getNext
while(n->getNext()!=nullptr){
if(n->getNext()->getKey()==key){ // the second call of getNext.
//...
The function can be defined like
void removeByKey( LancElem &head, int key )
{
if ( head.getNext() != nullptr )
{
if ( head.getNext()->getKey() == key )
{
LancElem *current = head.getNext();
head.setNext( head.getNext()->getNext() );
delete current;
}
else
{
LancElem *n = head.getNext();
while( n->getNext() != nullptr && n->getNext()->getKey() != key )
{
n = n->getNext();
}
if ( n->getNext() != nullptr )
{
LancElem *current = n->getNext();
n->setNext( n->getNext()->getNext() );
delete current;
}
}
}
}
Now try to use this function to delete the first node with the value 4 of your list and the function you currently have and compare their results.

How to compare 2 linked lists in c++ and put matching data into another linked list

I want to compare two linked lists that contain book titles and then create a new linked list that only has the matching titles from the original lists. Currently I have already created both linked lists and can output both in alphabetical order. The problem comes when I try to compare and create the updated list with the matching titles.
I have tried to create a recursive function that takes in both lists as parameters and will call itself and move the second list to the next node if the titles don't match.
If they both match, then it again calls itself, but moves both lists up a node.
I'm still pretty new on using linked lists and recursion, but I feel like I'm on the right track. All of my other functions are working, I'm just not sure how to make this work and also how to call it in my main function.
Node *compare(Node *h, Node *j) {
Node* h_curr = h;
Node* j_curr = j;
Node* new_node;
Node* updated_list = NULL;
while ((h_curr->next != NULL) || (j_curr->next != NULL)) {
if (h_curr->data != j_curr->data) { // if not equal, then move j_head to the next link
compare(h_curr, j_curr->next);
//j_curr = j_curr->next;
}
else {
updated_list->data = h_curr->data;
new_node = newNode(updated_list->data);
return updated_list;
updated_list = updated_list->next;
compare(h->next, j->next);
}
}
return NULL;
}
#include<string>
#include<iostream>
//assumed node structure
struct Node{
Node(std::string str, Node* ptr = nullptr):data(str), next(ptr){}
std::string data{};
Node* next{};
};
//The following is your rucresive function
void compare(Node* & first, Node* & second, Node* & match) {
if(!first || !second ) return;//base case
if ( first -> data < second -> data) compare(first -> next, second, match );
else if ( first -> data > second -> data) compare(first , second -> next, match);
else{//match found
match = new Node{ first -> data};
compare(first , second -> next, match -> next);
}
}
//To disply the result (recursive function)
void display(Node* & root){
if(!root) return;
std::cout<<root->data<<" ";
display( root-> next);
}
//To test
int main(){
Node* first = new Node{"aaa"};
first->next=new Node{"ccc"};
first->next->next=new Node{"ccc1"};
first->next->next->next=new Node{"ccc3"};
first->next->next->next->next=new Node{"ccc4"};
first->next->next->next->next->next=new Node{"ddd"};
Node* second = new Node{"baaa"};
second->next=new Node{"ccc"};
second->next->next=new Node{"ccc1"};
second->next->next->next=new Node{"ccc2"};
second->next->next->next->next=new Node{"ccc4"};
Node* res;
compare(first, second, res);
display(res);
}

Binary tree implementation for language analyse - child as node: does not work

I have been trying for some time to implement an AST in C++ to store data that has been derived from an ML language, here is an instruction that my AST manages to record:
var foo = 8;
The lexer isolates the tokens, and the parser infers that it is a variable declaration, so it isolates the whole:
foo = 8
From this it was easy to build a temporary AST:
=
/ \
foo 8
But I still can't handle the child-nodes:
foo = 2 + 4
Or
foo : integer = 2 + 4
So who should give this:
=
/ \
/ \
: +
/ \ / \
/ \ 2 4
foo integer
Here is my implementation attempt:
*.hpp
enum NodeTypes { /* ... */ };
struct Node {
token_t NodeValue;
NodeTypes NodeType;
Node *LeftChild = NULL;
Node *RightChild = NULL;
Node(token_t value, NodeTypes type);
void InsertLeft(token_t NodeValue, NodeTypes NodeType = NOTHING);
void InsertRight(token_t NodeValue, NodeTypes NodeType = NOTHING);
void BrowseUp();
};
*.cpp
Node(token_t value, NodeTypes type) {
NodeValue = value;
NodeType = type;
}
void InsertLeft(token_t value, NodeTypes type) {
if (LeftChild == NULL)
LeftChild = new Node(value, type);
else {
Node NewNode = Node(value, type);
NewNode.LeftChild = LeftChild;
LeftChild = &NewNode;
}
}
void InsertRight(token_t value, NodeTypes type) {
if (RightChild == NULL)
RightChild = new Node(value, type);
else {
Node NewNode = Node(value, type);
NewNode.RightChild = RightChild;
RightChild = &NewNode;
}
}
void BrowseUp() {
std::cout << NodeValue.value << " ";
if (LeftChild) LeftChild->BrowseUp();
if (RightChild) RightChild->BrowseUp();
}
Using it:
Node main = Node(NodePosition, NodeType);
SetMainAst(main, expr);
main.BrowseUp();
SetMainAst:
void SetMainAst(Node &node, Expr expr, NodeTypes type = NodeTypes::NOTHING) {
std::array<Expr, 3> exp = CutExpr(expr, GetNodePosition(expr));
Expr left = exp[0], right = exp[2];
token_t value = exp[1][0];
if (type == NOTHING) node.NodeValue = value;
if (!ContainNodes(left)) node.InsertLeft(left[0]);
else SetMainAst(node, left, DetermineFirstNode(expr));
if (!ContainNodes(right)) node.InsertRight(right[0]);
else SetMainAst(node, right, DetermineFirstNode(expr));
}
CutExpr() allows to cut an expression in 3:
lvalue ;
node ;
rvalue.
I helped myself with this (it's in python, but I transcribed it in C++).
With a single node expression, it works wonders. But, when there is more than one node, it no longer works: BrowseUp() stops the program after displaying the main node (i.e. the equal sign in this case).
I really don't understand, but I well followed the tutorial well and think I transcribed well in C++... Maybe it's a pointer/reference problem?
I would be very grateful if you would help me solve this problem (which has been bothering me for 3 days).
This
Node NewNode = Node(value, type);
NewNode.LeftChild = LeftChild;
LeftChild = &NewNode;
is wrong because you are storing a pointer to an object that is about to be destroyed (when you exit the if ... else statement).
You probably want something like this
Node* NewNode = new Node(value, type);
NewNode->LeftChild = LeftChild;
LeftChild = NewNode;
You're transcribing from Python which has garbage collection to C++ which doesn't. Therefore you have to add memory management yourself.

Interview Coding - Take a pointer to a Node structure as a parameter and return a complete copy of the passed-in data structure

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);
}