C++ constructor that deep copies a linked list - c++

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.

Related

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.

C++ Deep Copying Linked List

First of all, this is part of an assignment I'm currently trying to figure out. I'm trying to create a copy constructor that deep copies a given LinkedList.
I have coded the LinkedList methods already.
Here's the necessary parts of the LinkedList.h file.
LinkedList.h
private:
struct node {
Val data;
node* next = nullptr;
};
typedef struct node* nodePtr;
nodePtr head = nullptr;
nodePtr current = nullptr;
nodePtr temp = nullptr;
};
The parameters are given: "LinkedList::LinkedList(const LinkedList & ll)"
ll is the linked list to be copied.
I first tested if there is a head in the linked list, if not then that means the linked list is empty.
Then I copied the head from the old list to the new list.
I then set the new current to the head in preparation for the while loop.
Inside the while loop, I am copying the data of the current node as well as the pointer to the next node.
At the end I set the next pointer to nullptr to signify the end of the new list.
LinkedList.cpp
LinkedList::LinkedList(const LinkedList & ll){
if (ll.head == nullptr) {
return;
}
head = ll.head;
current = head;
while (ll.current->next != nullptr) {
current->data = ll.current->data;
current->next = ll.current->next;
}
current->next = nullptr;
}
I'm not sure if this is deep copying or not.
I also know that ll.current's starting position is not at the head.
I tried ll.current = ll.head. However, since it is given that this function is const. I can't set it like that.
There is also another function given:
LinkedList & LinkedList::operator=(const LinkedList & ll)
{
}
That I suspect may be needed. I'm hoping it optional that I use this.
You need to allocate new memory or new list elements as you add them, change your code to do the following:
// LinkedList.cpp
LinkedList::LinkedList(const LinkedList & ll)
{
if (ll.head == nullptr)
return;
// Create a temp variable since ll.current doesn't move/change.
node* tmp = ll.head;
// Allocate a new node in memory.
head = new node;
// Copy over the value.
head->data = tmp->data;
// Set the 'next' value to null (the loop will fill this in).
head->next = nullptr;
// Point 'current' to 'head'.
current = head;
// Move to next item in ll's list.
tmp = tmp->next;
while (tmp != nullptr)
{
// Allocate new memory for a new 'node'.
current->next = new node;
// Point to this new 'node'.
current = current->next;
// Copy over the data.
current->data = tmp->data;
// By default set the 'next' to null.
current->next = nullptr;
// Move along ll's list.
tmp = tmp->next;
}
}
Also, in your class get rid of typedef node* nodePtr. There is no need for that, it's cleaner to simply use node* for head, current and temp. Lastly, don't forget in your class' destructor to clear out dynamically allocated memory:
LinkedList::~LinkedList()
{
current = head;
while(current != nullptr)
{
current = current->next;
delete head;
head = current;
}
}
This cannot work, as you never allocate new list elements for the actual list object (using the 'new' operator), but only reuse existing ones. Just think about what happens, if ll has more elements than the actual list?

Writing a copy constructor with singly linked lists?

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

How do I Implement the Big Three Correctly: Singly Linked List (C++)

I am writing a program that contains a singly linked list to hold a shopping list. Each node has the item name, quantity, and quantity description (i.e. dozen for eggs). Everything works find in the program except the destructor. I can't seem to find what is wrong with it though.
The driver will execute to the end where the code is return 0;, then the destructor is called and stops on the line delete current; with the message:
"Unhandled exception at 0x0FC7A9E8 (msvcr120d.dll) in Project 14.exe: 0xC0000005: Access violation reading location 0xFEEEFEE2.".
I've posted the implementation for the big three functions below. The default constructor initializes both pointers (first, last) as null and the nodeCount as 0.
I can't seem to find the problem. Any help?
List::List(const List& b)
{
Node* newNodePtr = new Node;
Node* nodeCopy = b.first;
newNodePtr = nodeCopy;
first = newNodePtr;
last = newNodePtr;
nodeCount++;
nodeCopy = nodeCopy->getNext();
while (last != b.last)
{
Node* newNode = new Node;
newNode = nodeCopy;
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
nodeCount++;
nodeCopy = nodeCopy->getNext();
}
}
List::~List()
{
Node* current = first;
while (current != nullptr)
{
Node* _next = current->getNext();
delete current;
current = _next;
}
first = nullptr;
last = nullptr;
}
List& List::operator=(const List& rho)
{
Node* current = first;
while (current != nullptr)
{
Node* _next = current->getNext();
delete current;
current = _next;
}
first = nullptr;
last = nullptr;
Node* newNodePtr = new Node;
Node* nodeCopy = rho.first;
newNodePtr = nodeCopy;
first = newNodePtr;
last = newNodePtr;
nodeCount++;
nodeCopy = nodeCopy->getNext();
while (last != rho.last)
{
Node* newNode = new Node;
newNode = nodeCopy;
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
nodeCount++;
nodeCopy = nodeCopy->getNext();
}
return *this;
}
EDIT: I've also added my push_back function as it is written:
void List::push_back(Node* newNode)
{
if (first == nullptr)
{
first = newNode;
last = newNode;
}
else
{
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
}
nodeCount++;
}
Alright I think I've figured in out. This code seems to work and it fits the driver provided by my professor. Below I've included the big three functions and all of the other functions they call:
List::List(const List& b)
{
this->copyList(b);
}
List::~List()
{
this->clearList();
}
List& List::operator=(const List& rho)
{
this->clearList();
this->copyList(rho);
return *this;
}
void List::clearList()
{
Node* current = first;
while (current != nullptr)
{
current = pop_front();
delete current;
current = first;
}
first = nullptr;
last = nullptr;
}
void List::copyList(const List& b)
{
first = nullptr;
last = nullptr;
nodeCount = 0;
Node *headNode = b.getFirst();
while (headNode != nullptr)
{
string des = headNode->getDescription();
string qNa = headNode->getQuantityName();
int qNu = headNode->getQuantityNumber();
Node* newNode = new Node(qNu, qNa, des);
push_back(newNode);
headNode = headNode->getNext();
}
}
Node* List::pop_front()
{
Node* saveFirst = first;
first = first->getNext();
nodeCount--;
return saveFirst;
}
void List::push_back(Node* newNode)
{
if (nodeCount == 0)
{
first = newNode;
last = newNode;
}
else
{
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
}
nodeCount++;
}
This may not solve your exact issue, but if you have the functions you mentioned, then pseudo-code to a copy constructor would look like this.
List::List(const List& b)
{
Node *headNode = b.getHeadNode();
while (headNode != NULL)
{
push_back(headNode->getDataFromNode());
headNode = headNode->getNextNode();
}
}
So basically, that in a nutshell is the entire copy constructor. You're basically starting from the first node in the list, getting the data from that node, and calling your push_back() to add the new data. I'm assuming that push_back() does all of the tricky work of creating a node, adding the data to it, and placing it correctly at the back of the list.
Note how small, compact, and intuitive this implementation is. We know that all we need to do to create a copy of a linked list is to first make sure the list is empty (which it is for a new object), and keep adding the items from the old list to the new list. Since push_back() adds an item to a list (and has all the complexity of creating a node and linking it to the end node), we use it in a smart way to create our copy.
Note that you also need an assignment operator to go along with the copy constructor. The assignment operator in the example is simply calling clear() (if you have such a function) to remove all the nodes before proceeding.
Remember that all of this requires that your push_back() function works flawlessly. It should know how to properly handle inserting at the end of an empty and non-empty list.
Edit:
If your driver code does create the new node before the push_back (therefore push_back doesn't allocate the new node), then the alternative code can be used:
List::List(const List& b)
{
Node *headNode = b.getHeadNode();
while (headNode != NULL)
{
Node *newNode = new Node(headNode->getDataFromNode());
push_back(newNode);
headNode = headNode->getNextNode();
}
}
In the alternate version, I'm assuming that the constructor for the new node can be created with the data as an argument. I personally don't like the design of having push_back() not do all of the work of creating the node, but that's another issue.
It will depend at least in part on what first is pointing to when you call the destructor.
Your code is not copying the contents of the nodes. Instead it is only manipulating pointers so, as dyp pointed out, you have a leak with:
Node* newNodePtr = new Node;
Node* nodeCopy = b.first;
newNodePtr = nodeCopy;
You might want to read up on the copy-swap idiom.
What is the copy-and-swap idiom?

Deep copy and deconstructor sentinel linked list using Nodes

I am currently making a linked List program using Nodes(not that i know of any other way) and I have come upon a problem about creating a deep copy and getting rid of all my Nodes and Sentinels with my ~List(). Deleting the Nodes is not a problem, but the sentinels are since the first one is not assigned a index value.
List::~List()
{
for(size_t i=0; i<size; i++)
{
_setCurrentIndex(i);
if(current && curent->next == NULL)
{
Node *temp = current->next;
delete temp;
delete current;
}
else
{
Node *old = current;
current = current->next;
delete old;
}
}
}
List::List(const List & orig)
{
for(size_t i=0; i<size; i++)
{
if(i==0)
{
Node *copyFront = new Node; //the first sentinel
copyFront->data = orig.front->data; //front is defined in private in list.h
copyFront->prev = NULL; // it is defined as a Node (same for rear)
}
else if(0<=i && i<size) //put in i<size b/c 0<=i would always be true
{
_setCurrentIndex(i) //sets what current is and currentIndex which pts to diff Nodes
Node *copy = new Node;
copy->data = current->data;
copy->next = current->next;
current = current->next;
}
else if(i+1 == size)
{
Node *copyRear = new Node; //making the last sentinel, but it has to be
copyRear->data = orig.rear->data; //after data Node
copyRear->next = NULL;
}
}
}
I am seeking advice and comments on this code on how to proceed next or what to change if something is dreadfully wrong!
Linked lists are templates allowing any type of variable to sit in them. In my honest opinion, you'd be best off using the std::list which requires the #include <list> header file.
Of course, if you really want the experience of writing a linked list class yourself then the following code makes a deep copy of a list:
List::List( const List& other) {
if( other.head_ != nullptr) {
head_ = new Node( other.head_->item_); // copy first node
assert( head_ != nullptr); // ensure that the memory was allocated correctly
// copy the rest of the list
Node* pnew = head_;
// loop through the list until you reach the end (i.e. a node that's nullptr)
for( Node* porig( other.head_->next_); porig != nullptr; porig = porig->next_) {
// assign the next node in the destination list to the next node in the paramter's list
pnew->next_ = new Node( porig->item_);
assert( pnew->next_ != nullptr); // ensure that the memory was allocated correctly
pnew = pnew->next_; // move onto the newly created node in the destination list
}
}
else
// if the parameter is empty then the destination list will be empty as well
head_ = nullptr;
}
As for the destructor, you just need to run through the list deleting the nodes as you go:
List::~List() {
while( head_ != nullptr) { // keep looping until the list gets to the end
// make a second pointer to the node you are about to delete (so you don't lose track of it)
Node* pn( head_);
// move the head_ onto the next node essentially "removing" the first node from your list
head_ = head_->next_;
// delete the node that you've just "removed" from your list
delete pn;
}
}
I've tried to make the comments clear up anything that might be unclear.