Writing a copy constructor with singly linked lists? - c++

I'm writing a copy constructor that copies for example S to R; Set R(S);. S is a sorted singly linked list containing some ints (with a dummy node in the beginning).
Set::Set (const Set &source)
{
Node* sourceNode = source.head->next;
head = new Node(0, nullptr);
Node* nodeHead = source.head->next;
Node* p;
if (!sourceNode) {
std::cout << "Empty !" << endl;
}
else{
while (nodeHead) {
for (p=sourceNode; p->next; p=p->next) {
;
}
head->next = new Node(nodeHead->value,nullptr);
head = head->next;
nodeHead = nodeHead->next;
}
}
}
Right now it crashes and if i remove head = head->next; it will set S to { 5 }.
This is the constructor:
class Node
{
public:
Node (int, Node*);
private:
int value;
Node* next;
};
Why doesn't this work? This is my first experience with pointers so keep that in mind please.

Let's assume you have a function that adds to the end of the linked list. The copy constructor in this case would be very simple:
Set::Set (const Set &source) : head(0)
{
Node* sourceNode = source.head;
while (sourceNode != NULL )
{
addToList(sourceNode->value);
sourceNode = sourceNode->next;
}
}
The addToList would be the function that adds a node to the back of the list. All the copy constructor has to do is start off with an empty list, and in a loop, add items from the source list until the number of items in the source list is exhausted. This method, given that the addToList function is coded correctly, is guaranteed to work, and avoids code duplication.
This is the easiest way to implement the copy constructor. If you have no function that adds to the back of the list, now would be the good time to add it since you will need to to have such a function in any event.

Here is some code
LinkList(LinkList const & temp) // Copy constructor
{
this->head = 0; // calling list head
Node* tempHead = temp.head; /*For temprory store of head of link list*/
while (tempHead != 0)
{
this->insertAtEnd(tempHead->data);
tempHead = tempHead->next;
}
}
void insertAtEnd(int val)
{
Node* temp = new Node;
temp->data = val;
temp->next = 0;
Node* curr = this->head;
if (curr != 0)
{
while (curr->next != 0)
{
curr = curr->next;
}
curr->next = temp;
}
else
{
this->head = temp;
}
}

Related

C++ Need help on Remove Node function

I have stressed my head out the last few days to figure out how to get this remove() function to work. I'm still a student and data structure is no joke.
I really need help on how to get this function to remove a specific number on the list from user input. Doesn't matter what I try, it still could not work right.
For example, the list is: [1, 2, 3]
I want to delete number 2 on the list. I want the remove() function to traverse thur the list, if it found number 2, then delete number 2.
class SortedNumberList {
public:
Node* head;
Node* tail;
SortedNumberList() {
head = nullptr;
tail = nullptr;
}
void Insert(double number) {
Node* newNode = new Node(number);
if (head == nullptr) {
head = newNode;
tail = newNode;
}
else {
tail->SetNext(newNode);
tail = newNode;
}
}
// Removes the node with the specified number value from the list. Returns
// true if the node is found and removed, false otherwise.
bool Remove(double number) {
Node* temp = head;
if (temp == nullptr) {
return false;
}
if (head->GetData() == number) {
head = head->GetNext();
return true;
}
else{
while (temp != nullptr) {
Node* curNode = temp;
Node* preNode = nullptr;
preNode = curNode->GetPrevious();
temp = temp->GetNext();
if (curNode->GetData() == number) {
preNode = curNode->GetNext();
return true;
}
delete curNode;
}
}
delete temp;
}
};
class Node {
protected:
double data;
Node* next;
Node* previous;
public:
Node(double initialData) {
data = initialData;
next = nullptr;
previous = nullptr;
}
Node(double initialData, Node* nextNode, Node* previousNode) {
data = initialData;
next = nextNode;
previous = previousNode;
}
Edit: I'm able to solve my own issue, thank you everyone.
bool Remove(double number) {
// Your code here (remove placeholder line below)
Node* temp = head; //Make a temporary node point to head.
if (temp == nullptr || head == nullptr) { //if user don't provide input, return false.
return false;
}
if (head->GetData() == number) { //If number need to delete is at head.
head = head->GetNext();
return true;
}
else {
while (temp != nullptr) { //Travese temp node throught out a list.
Node* curNode = temp->GetNext(); //Make a current node point at temp next.
Node* preNode = temp;
Node* sucNode = curNode->GetNext();
if(curNode->GetData() == number) { //Delete a node if number is found on the list
if (curNode->GetNext() == nullptr) { //Delete at tail.
preNode->SetNext(nullptr);
tail = preNode;
delete curNode;
return true;
}
if (curNode->GetNext() != nullptr) {
preNode->SetNext(sucNode);
sucNode->SetPrevious(preNode);
delete curNode;
return true;
}
}
temp = temp->GetNext();
}
}
return false;
}
};
You should make Node a friend class of SortedNumberList or define former inside the later class which simplifies the code somewhat. It's personal preference but it leads to less unnecessary boilerplate code (getters and setters).
In a double linked list you do not need to keep track of the last as you do need on single linked lists because you have both pointers available.
The quest is just a matter of iterating to find the value, taking care to cut it early when we pass the mark since it is a sorted list.
Then delete the object and update the link pointers.
bool Remove(double number) {
// Loop through the entire list
Node* temp = head;
while ( temp != nullptr) {
// There is no point looking forward if the list is sorted
if (temp->data > number ) return false;
// Compare to find
if (temp->data == number) {
// Get the pointers so we can delete the object
Node* prev = temp->previous;
Node* next = temp->next;
// Delete object
delete temp;
// Update previous pointers
if ( prev==nullptr ) {
head = next;
} else {
prev->next = next;
}
// Update next pointers
if ( next==nullptr ) {
tail = prev;
} else {
next->previous = prev;
}
// Indicate success
return true;
}
}
// We iterated to the end and did not find it
return false;
}

algorithm for finding a node in a linked list

what is the algorithm used to write Snode* find and set& operator=( set &rhs) I just can't understand these two. I can read the code but I can't figure out why are they there. I can't understand the steps of the used algorithm.
Things I already figured out:
1. Snode is a function that gets a value and returns the node with the same data.but what do prev and previous do and what is **previous and why ahould we create a pointer to a pointer?
2. set& operator= is for overriding the = operator. but I can't understand what does it do after overriding.and why should we swap the heads of temp and rhs sets.
here's the code:
#include <iostream>
using namespace std;
struct Snode //Snode class defines a node in a list
{
char data;//a node includes a character
int count;//an integer to count the occurrence
Snode *next = NULL;//and a pointer to the next node
Snode(char data, Snode* next) : data(data), next(next) {}
};
class set
{
private:
Snode *head;//first node in the list
Snode *tail;//last node of the list
public:
set() : head(NULL), tail(NULL)
{
}
set( set &src) : head(NULL), tail(NULL)//copy constructor method
{
Snode *temp = src.head;//set head of the second list as temp to travers
while (temp)//untill the end of the list
{
// insert(temp->data);
Snode *newNode = new Snode(temp->data,NULL);//create a new node with the same data and count
newNode->count = temp->count;
//now puts it in the right place
if (!head)//if head = NULL (if sset is empty)
head = newNode;//set the new node as the first node
if (tail)//if tail != NULL (if set isn't empty)
tail->next = newNode;//set new node as the next node of current tail, so it'll be the tail
tail = newNode;
temp = temp->next;//does the same thing for all the nodes of the second list
}
}
~set()//destructor method
{
Snode *temp = head;
while (temp)//traverse the list and delete each node
{
Snode *next = temp->next;
delete temp;
temp = next;
}
}
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
}
return *this;
}
bool isAvailable(char value)//checks if any node with the same data exists or not
{
return (find(value) != NULL);//if find function can't find any, there's no same node
}
Snode* find(char value, Snode **previous = NULL)
{
if (previous)
*previous = NULL;
Snode *temp = head;
Snode *prev = NULL;
while (temp)
{
if (temp->data == value)
{
if (previous)
*previous = prev;
return temp;
}
temp = temp->next;
}
return NULL;
}
bool isFirst(char value)
{
return ((head) && (head->data == value));//if head's data is equal to value returns true
}
bool isLast(char value)
{
return ((tail) && (tail->data == value));//if tail's data is equal to value returns true
}
void display()
{
Snode *temp = head;
while (temp)
{
cout << temp->data << " " << temp->count+1 << "\n";
temp = temp->next;
}
}
void insert(char value)//to insert a new value
{
Snode *temp = find(value);//if a node with the same data alreay exists
if (temp)
temp->count += 1;//increase the count by one
else
{
temp = new Snode(value,NULL);//if if a node with the same data doesn't exist
if (!head)//if list is empty
head = temp;
if (tail)//if list is not empty
tail->next = temp;
tail = temp;
}
}
int count(char value)//count the nodes by the counter temp
{
Snode *temp = find(value);//travers the set
return (temp) ? temp->count : 0;//if the list is empty return 0, else return the counter
}
void deleteFirst()//deletes the first node
{
if (head)//if list isn't empty
{
Snode *temp = head;
head = head->next;//move the head forward
if (tail == temp)//if loop faced the tail
tail = NULL;
delete temp;//delete the data
}
}
void deleteLast()//delete the last node
{
if (head)
{
Snode *last = head;
Snode *previous = NULL;
while (last->next)//move forward untill the node before the last one
{
previous = last;
last = last->next;
}
if (previous)//at the end of the list
previous->next = NULL;
tail = previous;
if (head == last)//if there's only one node
head = NULL;
delete last;
}
}
void remove(char value)//remove the node with the same data as the entry
{
Snode *previous;
Snode *temp = find(value, &previous);
if (temp)
{
if (temp->count > 1)
temp->count -= 1;
else
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
if (tail == temp)
tail = previous;
delete temp;
}
}
} };
As you have guessed, find tries to locate a Snode containing the required character. If only that is required, you can ignore the previous parameter (it will be NULL), and previous/prev processing will just be useless.
But find is used in remove... In order to remove a node in a singly linked list, you must have the previous one point to the next one. So you must browse the list keeping a track of the previous node. That is exactly the way it is used in remove with:
if (previous)
previous->next = temp->next;
The assignment operator uses a close variant of the copy and swap idiom. But as the destructor only uses the head member, only that member is swapped: that will be enough to have the destructor of temp to destroy all nodes of the original list.
Simply tail should be set in this even if it is useless to set it in tmp. A correct implementation could be:
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
tail = temp.tail; // no need for a full swap here
}
return *this;
}

C++ Singly Linked List Copy Constructor Segmentation Fault

I'm trying to create a deep copy constructor of a singly linked list class. It copies the head of the new list and appends elements to the end of it (by calling an append) function.
The full code is available here: https://onlinegdb.com/Hke0ev8bG
Can anyone point out where I'm going wrong? Much appreciated!
class LinkedList
{
class Node
{
public:
int *data;
Node *next;
Node() {
data = NULL;
next = NULL;
}
Node(int *d) {
data = d;
next = NULL;
}
};
private:
Node *head;
int itemCount;
public:
LinkedList() {
head = NULL;
itemCount = 0;
}
//COPY CONSTRUCTOR
LinkedList(LinkedList &copy)
{
Node *temp = copy.head;
while (temp != NULL)
{
append(temp->data);
temp = temp->next;
}
}
//ADD TO THE END OF A LIST
void append(int *d) {
Node *tail = new Node;
tail->data = d;
tail->next = NULL;
if (head == NULL) {
head = tail;
}
else {
Node *temp = new Node;
temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = tail;
}
itemCount++;
}
The problem is that the program runs into a "Segmentation fault" at the copy constructor part.
You forgot to initialize LinkedList::head and LinkedList::itemCount in the copy constructor. The initialization performed in the regular constructor only applies when the regular constructor is actually used.
As a result, LinkedList::append sees random garbage when checking the head pointer, assumes it's valid and then causes a seg fault when using that invalid pointer.

Implementing copy constructor in a single linked list C++

I have a C++ code:
#include <iostream>
using namespace std;
struct Node;
typedef Node *NodePtr;
struct Node
{
int Item;
NodePtr Next;
};
class LinkedList
{
public:
LinkedList(); // default constructor
~LinkedList(); // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
};
LinkedList::LinkedList()
{
Head = NULL; //declare head as null
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr Crnt;
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
//if head is in null declare the added node as head
if (Head == NULL)
{
Head = node;
}
else
{ //set the current to head, move the current node to current next node
Crnt = Head;
while (Crnt->Next != NULL)
{
Crnt = Crnt->Next;
}
//Add item to the tail of the linked list
Crnt->Next = node;
}
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb;
return 0;
}
So my question is how do I implement a copy constructor(suppose on object lb) that makes a deep copy of the list argument and also adding code for testing the copy constructor on empty and non-empty lists?
Thanks in advance.
One of the big rules of programing is Don't Repeat Yourself (DRY). If you have a function that adds and you know it works, keep using it for add-related jobs. This means it's in your best interest to keep add dead stupid and versatile.
Applying the DRY philosophy, the Copy Constructor, assuming the AddTail method works correctly, is astonishingly simple: Call AddTail for every node in the source list.
LinkedList::LinkedList(const LinkedList & src):Head(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
And having a working copy constructor makes the assignment operator, thanks to the Copy and Swap Idiom, also laughably simple:
LinkedList & LinkedList::operator=(LinkedList src)
// pass by reference performs the copy
{
std::swap(Head, src.Head); // now just swap the head of the copy
// for the head of the source
return *this;
} // destructor fires for src and cleans up all the nodes that were on this list
To finish off The Rule of Three trifecta we need a destructor. This, like
the copy constructor is an application of DRY: Call your node removal function over and over until the list is empty. A removal function is an almost certain requirement of any linked list, so here I'm going to assume that there is one called Remove.
LinkedList::~LinkedList()
{
while (Head != nullptr)
{
NodePtr temp = Head;
Remove(Head);
delete temp;
}
}
So now based on two functions that a Linked List cannot function without anyway we have implemented all of the other functions required for basic maintenance. All you need are tested and bug-free Add and Remove functions and the rest comes practically free of charge.
And because the AddTail function hits one of my pet peaves... Here is a trick to greatly reduce the complexity of the function:
void LinkedList::AddTail(int Item)
{
NodePtr *Crnt = &Head; // instead of pointing where Head points, point at
// Head now we don't care if it is head or any
// other node's Next. They are all abstracted to
// the same thing: A pointer to where the next
// node can be found
while (*Crnt != NULL) // keep looking until end of list
{
Crnt = &(*Crnt)->Next; // by pointing at the next Next pointer
}
//Add item to the tail of the linked list
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
*Crnt = node; // Now just plop the new node over top of the terminating NULL
}
The Remove function, which I'm leaving unimplemented, uses the same pointer -to-pointer trick.
try this (https://ideone.com/9lywXc using your original posted code)
LinkedList::LinkedList(const LinkedList& other):Head(nullptr)
{
cout << "copy constructor called:\n";
if(other.Head == nullptr) return;
NodePtr dummyHead = new Node;
NodePtr curr = dummyHead;
NodePtr othcurr = other.Head;
for(; othcurr!=nullptr; othcurr = othcurr->Next)
{
curr->Next = new Node;
curr = curr->Next;
cout << (curr->Item = othcurr->Item) << ",";
curr->Next = nullptr;
}
Head = dummyHead->Next;
delete dummyHead;
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
return 0;
}
output:
copy constructor called:
30,60,90,
this is an improvement on user4581301 prior answer so that copy constructor is O(n) on input list size. keep track of the tail with a single extra pointer in your encapsulating list class:
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
//KEEP TRACK OF TAIL POINTER WITH EXTRA MEMBER
NodePtr Tail;
};
//via user4581301 response
LinkedList::LinkedList(const LinkedList & src):Head(nullptr),Tail(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr np = new Node{Item,nullptr};
if(Tail == nullptr && Head == nullptr)
Head = Tail = np;
else
{
Tail->Next = np;
Tail = Tail->Next;
}
}
regarding testing:
you can add functionality to spit out the contents of the list. or you can subclass it into a test extension. or you can break encapsulation like this, using operator<<() :
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
//breaks encapsulation but make some nice sugar to look inside
friend ostream& operator<<(ostream& s, LinkedList& l)
{
s << "list contents: ";
NodePtr c = l.Head;
for(; c!=nullptr;c=c->Next)
s << c->Item << " ";
s << endl;
return s;
}
private:
NodePtr Head;
NodePtr Tail;
};
so that
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
cout << lb;
return 0;
}
spits out:
list contents: 30 60 90

C++ constructor that deep copies a linked list

I am a noob to C++ and programming in general and am trying to make a constructor which will duplicate a linked list. The idea is that I can use
Individual* copyOfList = new Individual(originalList->getFirstBit());
to make a deep copy of the original list.
But my cose below seems not to be doing a deep copy. When I edit the copyOfList the originalList is affected as well. And I don't understand linked lists enough to make it deep copy. Can someone help me please.
Individual::Individual(BinaryNode * copyHead)
{
head = copyHead;
NodePtr last = NULL;
NodePtr temp = NULL;
curr = head;
while (curr != NULL)
{
temp = new BinaryNode(curr->data, NULL);
if (last != NULL)
{
last->next = temp;
}
last = temp;
if (head == NULL)
{
head = temp;
}
curr = curr->next;
}
}
Here is the BinaryNode code
class BinaryNode
{
public:
BinaryNode();
BinaryNode(bool the_data, BinaryNode *next_link);
bool data;
BinaryNode *next;
private:
};
This is the original list code. I think the order I populated it is adding to the head.
if(the_length > 0)
{
srand(time(NULL));
int randnumber;
NodePtr temp = new BinaryNode;
for(int i = 0; i < the_length; i++)
{
randnumber=(rand() % 2);
temp = new BinaryNode(randnumber,head);
head = temp;
}
}
head = copyHead;
With the above statement, head is pointing to the same memory location where copyHead is pointing to. Loop is not entered on an empty list. But in the loop -
if (head == NULL)
{
head = temp;
}
This can never be the case on an linked list to be copied that has childs. So, you are never updating the head of the linked list and instead it is still pointing to the starting node of the linked list to be copied. Try -
Individual::Individual(BinaryNode * copyHead)
{
if (NULL == copyHead)
{
// Empty list
return;
}
head = new BinaryNode(copyHead->data, NULL);
curr = head;
copyHead = copyHead->next;
while (NULL != copyHead)
{
// Copy the child node
curr->next = new BinaryNode(copyHead->data, NULL);
// Iterate to the next child element to be copied from.
copyHead = copyHead->next;
// Iterate to the next child element to be copied to.
curr = curr->next;
}
}
Hope it helps !
I'm assuming Individual is a class in your code and basically it's holding the head possition of the list. I mean:
class Individual{
private:
void* head;// may be anything*
public:
void* getHead()
{
return head;
}
// all the methods
}
Now c++ provide a special type of constructor i.e. Copy Constructor. If you don't define a one compiler provide a default copy of copy constructor which do a shallow copy of a object. To define your custom copy constructor:
Firstly add a new method in BinaryNode:
void link(BinaryNode& b)
{
b.next=this;
}
Individual::Individual(const Individual& args)
{
void* copyHead = args.getHead()
if ( copyHead==nullptr)
{
// Empty list
return;
}
head = new BinaryNode(copyHead->data, NULL);
curr = head->next;
copyHead = copyHead->next;
temp = head;
while (NULL != copyHead)
{
// Copied the child node
curr = new BinaryNode(copyHead->data, NULL);
curr.link(temp);
temp = curr;
// Iterate to the next child element to be copied from.
copyHead = copyHead->next;
// Iterate to the next child element to be copied to.
curr = curr->next;
}
}
Now as you want to to a deep copy You have to implement a code that will copy the whole list starting from the head pointer.