Linked list copy constructor - c++

I originally had to create my own linked list with using the STL. Now, I am to implement a copy constructor method and I am having real difficulty understanding it. Have a test on this in a few days so I would really like to get it clear. (Test is closed book so need to really).
The List contains a EmployeeNode pointer *head. The EmployeeNode contains an Employee and a pointer to the next EmployeeNode. The Employee class contains a name and salary.
The method seems to get caught in the for loop when trying to copy the 3rd node over. I think this is because I overwrite the newNode but I do not know how to solve this.
ListOfEmployee::ListOfEmployee(const ListOfEmployee &obj)
{
head = NULL;
if(obj.head != NULL)
{
EmployeeNode *newNode = new EmployeeNode("", 0);
EmployeeNode *tempPtr;
EmployeeNode *newPtr;
//using the temp pointer to scroll through the list until it reaches the end
for(tempPtr = obj.head; tempPtr->next !=NULL; tempPtr = tempPtr->next)
{
if(head == NULL)
{
cout<<"Attempts to initialize the head"<<endl;
head = newNode; //assinging the new node to the head
newNode->emp.name = tempPtr->emp.name;
newNode->emp.salary = tempPtr->emp.salary;
cout<<"Initializes the head"<<endl;
}
else
{
cout<<"Attempts to add a new node"<<endl;
//using the temp pointer to scroll through the list until it reaches the end
for(newPtr = head; newPtr->next !=NULL; newPtr = newPtr->next)
{
cout<<"Looping through the list"<<endl;
}
//assiging the last place to the new node
newPtr->next = newNode;
newNode->emp.name = tempPtr->emp.name;
newNode->emp.salary = tempPtr->emp.salary;
cout<<"Adds a new node"<<endl;
}
}
}
}

In your code where you are adding newNode in newPtr->next = newNode; you are basically using previously allocated node. You should create a new node using new. Something like:
newPtr->next = new EmployeeNode("", 0);
newNode = newPtr->next;
newNode->emp.name = tempPtr->emp.name;
newNode->emp.salary = tempPtr->emp.salary;
Also you should set newNode->next = NULL; in your code.

Related

Adding a node to the beginning of a double-linked list

I am trying to create a function that adds a node to the beginning of a double-linked list in C++, and I'm getting this error in Xcode. I know it must be because I lost the address of one of my temp nodes, but I cannot figure out how to fix it.
template<typename Item>
void DLList<Item>::push_front(const Item &item) {
/* Adds item to a new Node at the front of the list. Updates head,
tail, and size accordingly. Must appropriately handle cases in which the list is empty */
Node*p = new Node;
p -> item = item;
Node*oldHead = head;
p -> next = oldHead;
oldHead -> prev = p; /*error message: Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)*/
head = p;
size ++;
}
The error will happen when oldHead is nullptr, and then oldHead->prev is an invalid access. This happens when the list is empty (head is nullptr).
It is easy to fix: just make sure you only execute that statement when the list is not empty. NB: you don't actually need oldHead. Just keep working with head.
And as the comment in your code seems to suggest your list has a tail member, you should set it when the first node is added to the list:
Node* p = new Node;
p -> item = item;
p -> next = head;
if (head != nullptr) {
head -> prev = p;
} else {
tail = p;
}
head = p;
size ++;

How can I assign the "this" pointer as "temp"?

I call a function interleave that looks like
void AddressLinkedList::interleave(AddressLinkedList& other) {
AddressLinkedList temp;
AddressListNode* thisCur = this->head;
AddressListNode* otherCur = other.head;
for (int i = 0; i < this->length + other.length; i++) {
if (i % 2 == 0) {
temp.insertEnd(thisCur->data);
thisCur = thisCur->next;
}
else if (i % 2 != 0) {
temp.insertEnd(otherCur->data);
otherCur = otherCur->next;
}
}
return;
}
This function is supposed to interweave a singly linked list A with a singly linked list B along the lines of if A looked like "1, 2, 3" and B looked like "4, 5, 6", then the call linkedListA.interleave(linkedListB) should make A "1, 4, 2, 5, 3, 6". I've successfully managed to create a list like this, the problem is it that it's the temp list, but I don't know how to make it so it would be the this pointer with an end goal linkedListA be the aforementioned "singly linked list A". In case it matters, below is the overloaded assignment operator and the insertEnd function.
void AddressLinkedList::insertEnd(const Address& value) {
if (length == 0) {
this->insertStart(value);
return;
}
AddressListNode* temp = new AddressListNode(value);
length++;
tail->next = temp;
tail = temp;
}
AddressLinkedList& AddressLinkedList::operator=(const AddressLinkedList& other) {
delete this;
AddressListNode* current;
current = other.head;
while (current != nullptr) {
insertEnd(current->data);
current = current->next;
}
return *this;
}
Since interleave is defined as a member function of AddressLinkedList it should modify (and work on) the object it was called on. So you don't need to (and you shouldn't) create a temporary list to use it to build your resulting collection and then "assign" it as this. It is possible with some new, delete and raw pointer trickery, but I wouldn't recommend this (the idea would be to create AddressListNode* as head and then assign that new head where the original one was, but you would also had to delete previous chain of AddressListNode* from original head to avoid memory leaks, as I said, not recommended).
Assuming that your code that calls this method looks like this:
AddressLinkedList A;
AddressLinkedList B;
... //inserting values to A and B
A.interleave(B);
Your interleave implementation should looks more like this (it's more of a proof on concept, than working solution, I didn't compiled it):
void AddressLinkedList::interleave(AddressLinkedList& other) {
AddressListNode* thisCur = head;
AddressListNode* otherCur = other.head;
while (thisCur != nullptr) { //assumig that last node points to nullptr
AddressListNode* nextNode = thisCur->next;
AddressListNode* otherNext = otherCur->next;
thisCur->next = otherCur; //attach it to node from other
thisCur = thisCur->next; //advance to next node
thisCur = nextNode; //reattach node that was originally after current
thisCur = thisCur->next; //advance again to next node
otherCur = otherNext ; //advance on other
}
other->head = nullptr; //loop above hijack nodes from other
}
All this code do is, it takes heads of both of your collection, iterate over this and for every node it attaches corresponding node from other. Effectively it will modify your object on which you originally called interleave method. However due to modifying AddressListNode pointer it will also destroy your original AddressLinkedList you passed as and argument to interleave. So you should probably modify it in a way that for thisCur->next = otherCur; actually create a copy of an Address and create new node.

Duplicating linked list to be sorted is deleting the original linked list

I am trying to sort my linked list based on salary so that it displays the highest salary at the top and so on. It parses through my original linked list and duplicates each node to be inserted into a new sorted linked list, in this case "head" is the head of my original and "sorthead" is the head of the duplicate.
static void sortingRecords2() {
EmployeeRecords * q = head;
while (q != NULL) {
EmployeeRecords * sortnode = NULL;
sortnode = q;
sortnode->next = NULL;
sortnode->prev = NULL;
if (sorthead == NULL) {
sorthead = sorttail = sortnode;
}
else if (sortnode->Salary >= sorthead->Salary) {
sortnode->next = sorthead;
sorthead->prev = sortnode;
sorthead = sortnode;
}
else {
temp2 = sorthead;
EmployeeRecords * previous = NULL;
while (temp2 != NULL) {
if (sortnode->Salary <= temp2->Salary) {
previous = temp2;
}
temp2 = temp2->next;
}
if (previous->next == NULL) {
sortnode->prev = sorttail;
sorttail->next = sortnode;
sorttail = sortnode;
}
else {
sortnode->next = previous->next;
sortnode->prev = previous;
previous->next = sortnode;
sortnode->next->prev = sortnode;
}
}
q = q->next;
}
displayRecords(head);
}
After testing out different methods to try and figure out where exactly is the problem, I've determined that the sorting algorithm works fine but after it is done executing and I call my display function it only displays the head of my original list. After executing this function, all other calls to my display function also only displays the head of my original list where previously it properly displays the whole list.
I'm not sure why exactly my main "head" is affected during execution when at the start I already used a temp value "q" to copy the head.
The immediate bug that jumps out at me is
sortnode = q;
is an assignment of addresses. sortnode and q now point at the same node. That means
sortnode->next = NULL;
sortnode->prev = NULL;
changes this shared node and blows the stuffing out of the source list, leaking all of the following nodes.
You will need to create a new node that is a copy of *q for sortnode to point at and build the sorted list with copies of the source nodes.
sortnode = new EmployeeRecords(*q);
is the start of a possible solution.

Merge two sorted Linked List

I had a doubt in this problem: link I am following this solution:
if((headA==NULL)&&(headB==NULL)
return NULL;
if((headA!=NULL)&&(headB==NULL))
return headA;
if((headA == NULL)&&(headB!=NULL))
return headB;
if(headA->data < headB->data)
headA->next = MergeLists(headA->next, headB);
else if(headA->data > headB->data)
{
Node* temp = headB;
headB = headB->next;
temp->next = headA;
headA = temp;
headA->next = MergeLists(headA->next, headB);
}
return headA;
I get that when headA->data < headB->data then we simply move the headA pointer to the next node. But when headA->data > headB->data, then we create a temp pointer, point it where headA is pointing and move headB to next node. What I don't get is:
How are the nodes which are previously sorted get linked to this new temp node that I have created? Can you please point it out on my code
Also, where is headA pointer pointing to after the second condition? Is it pointing at the new node?
The code effectively moves the head element from list B to list A.
Node* temp = headB;
headB = headB->next;
temp is pointing at the list B head, and headB is pointing at the list B tail. In effect, the list B head has been popped off the list.
temp->next = headA;
The list A is now appended to the popped head.
headA = temp;
And list A is now set to the list with the original head from list B followed by the original list A.
The merge then proceeds exactly as if list A had the smaller head, which it now does because the next element in list B cannot be smaller than it.
This code fails to handle the case that both lists have the same head data value. In that case, it just returns list A without merging the tails.
Not sure why you can't just do this for the last two cases:
if(headA->data < headB->data) {
headA->next = MergeLists(headA->next, headB);
return headA;
}
else {
headB->next = MergeLists(headA, headB->next);
return headB;
}
And keep it simple and symmetric.
You can also simplify the first three cases to the following two:
if(headA == NULL)
return headB;
if(headB == NULL)
return headA;
This can also be done without recursion:
Node *merge_lists(Node *headA, Node *headB)
{
Node *head;
Node **nextPtr = &head;
while (headA && headB) {
Node **headMin = (headA->data < headB->data) ? &headA : &headB;
*nextPtr = *headMin;
nextPtr = &(*headMin)->next;
*headMin = *nextPtr;
}
*nextPtr = headA ? headA : headB;
return head;
}

Adding to a Sorted Doubly LinkedList (C++)

I've implemented a program that creates a sorted doubly linked list. Everything works fine except the fact that I can't seem to figure out where program is accepting the node 66 as head, and 44 (which is smaller) as the node after. Here's my add function.
bool SortedDoublyLinkedList<ItemType>::add(const ItemType &newEntry) {
Node<ItemType> *newNode = new Node<ItemType>();
newNode->setItem(newEntry);
if (size == 0) //checks if linked list is empty -> add elements if so.
{
head = newNode;
newNode->setNext(NULL);
newNode->setPrev(NULL);
tail = newNode;
}
// checks if the new node to be added is small than node that head is currently pointing to. If so, add new node before head and make it the new head of list.
else if (newNode->getItem() < head->getItem()) {
head->setPrev(newNode);
newNode->setNext(head);
newNode->setPrev(NULL);
head = newNode;
}
// checks if new node is bigger than the tail node (or last node). If so, add new node to end of list. Then make that new node the tail (end) of list.
else if (newNode->getItem() > tail->getItem()) {
tail->setNext(newNode);
newNode->setNext(NULL);
newNode->setPrev(tail);
tail = newNode;
}
// if the new node is neither of the mentioned situations, add the new node in the correct position in middle of the list. TempPtr1 acts as a ptr and the new node will be added directly in front of it.
else {
Node<ItemType> *tempPtr1;
tempPtr1 = head;
while (newNode->getItem() > tempPtr1->getItem()) {
tempPtr1 = tempPtr1->getNext();
}
newNode->setPrev(tempPtr1->getPrev());
newNode->setNext(tempPtr1); // = tempPtr1;
tempPtr1->getPrev()->setNext(newNode);
tempPtr1->setPrev(newNode);
}
size++;
return true;
}
Output:
66
44
88
88