I have source code that adds items to linked list and prints them.
Now the "print()" function prints items from end to first. There are 2 questions:
1. is "99" the first item in linked list ?
2. if "11" is the first item in linked list, how i can set the start position of the list to print from first ?
#include <iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
};
Node *head = NULL;
int *start = &head->data; // Get start of linked list
void insert(int data)
{
Node *new_node = new Node();
new_node->data = data;
new_node->next = head;
head = new_node;
}
void display()
{
Node *ptr;
ptr = head;
while (ptr != NULL)
{
cout<< ptr->data << " ";
ptr = ptr->next;
}
}
int main()
{
for (int i = 11; i <= 100; i += 10)
insert(i);
cout<< "Setting head->data address...";
&head->data = start;
cout<< "[ OK ]\n";
cout<< "The linked list is: ";
display();
cout<< endl;
return 0;
}
1) If that for cycle that inserts elements should really end with i += 11, then yes, 99 is the first element in the list.
2) The list looks like this 99 -> 88 -> ... -> 22 -> 11. There is no way of getting from 11 to 22, you can only traverse the list in one direction. That's a characteristic of the list data structure.
If you need to print the elements in the same order you insert them, you need to insert at the end on the list, not at the front. For that head is not enough, you'd need another pointer to the list, one pointing to the end, let's call it tail. insert() would then use tail in much the same way as it uses head now (it would not touch or change head at all ).
Related
So basically I have this assignment on my University that asks to make a sorted singly linked list and then make some methods on it. The one that I'm having trouble is: "create delete() function that checks the average of each triple elements and if it's lower than integer 'K' (which is a parameter of said function) deletes the first element of the triple or deletes second and last element of the triple if it's higher."
I already made a function/method that deletes a single element of the linked list.
void LinkedList::deleteElement(int a)
{
Node *temp = head;
Node *previousTemp = head;
while(temp != nullptr)
{
if(temp->value == a)
{
break;
}
else
{
previousTemp = temp;
temp = temp->next;
}
}
if(temp == nullptr)
{
cout << "Can't delete. Element not found." << endl;
}
else
{
cout << "\nDeleting element: " << temp->value << endl;
previousTemp->next = temp->next;
delete temp;
}
howMany--;
}
void Sznur::deleteTriple()
{
Node *first = head;
Node *second = first->next;
Node *third = second->next;
}
The task is written pretty hard to understand but for ex.:
int K=3
linkedList: 7,6,6,3,3,3,2,1,1,1,1
after running the function:
linkedList: 7,3,1,1,1,1
(7+6+6)/3 > K -> deletes 6 and 6
(3+3+3)/3 > K -> deltes second 3 and last 3
(2+1+1)/3 < K -> deletes 2
If the linkedList length is not dividable by 3 the last elements stay in their place.
Try something like this.
void tripleFunc(Node* head, int K)
{
Node* nodePtr = head; // nodePtr always points at the start of a new triple
while (true)
{
Node* first = nullptr;
Node* second = nullptr;
Node* third = nullptr;
first = nodePtr; // When taking the three elements out, remember to always check for a null pointer BEFORE accessing the element
if (first)
second = first->next;
if (second)
third = second->next;
if (third)
nodePtr = third->next; // Keep the nodePtr pointing at the start of the next triple
else
return; // Only happens if one or more of the previous ifs failed, which means that we don't have enough elements left for a full triple
if (calculateAverage(first, second, third) < K) // Make this function
{
deleteElement(first->value);
}
else
{
deleteElement(second->value);
deleteElement(third->value);
}
}
}
I haven't tested it though, so any possible bugs are left as an exercise to the reader to find and sort out. :)
I am creating a linked list program, and one of the functions is supposed to remove a node at a given index.
My idea is to locate the node one before the node at the index I wish to remove, then set it's next pointer to the ->next pointer of the node I wish to remove, therefore "skipping" it and removing it from the list.
At the moment my for loop does not seem to be working. After the the for loop has run, the value of temp->data is always the data of the second node in the list.
for example, with the list of nodes
15
14
13
12
11
10 (10 being the start of the list)
if I want to remove at the index of 4.
temp->data returns 11, instead of 14.
Here is the code I have:
NODE * removeAt(NODE * pList, int index)
{
NODE * temp = pList;
for (int i = 0; i < index - 1; i++)
{
temp = temp->next;
}
NODE * next = temp->next->next;
temp->next = next;
return temp;
}
Any help is appreciated!
First of all, you have an indexing convention problem. If you say you expect the-next-after-removed to be 14, that means you want to remove the number 13. But it is a number 3 if you start from 0.
You say "My idea is to locate the node one before the node at the index I wish to remove". Imagine you want to remove the start node (data=10), will your idea work here? There is no any "one before" node in this case. Same about the last. There would be no the-next-after-removed.
Also, you need to check for null pointers everywhere. And you must destroy the removed node to avoid memory leaks.
And you need to check how do you insert nodes. Is the start one really 10?
I would improve your code like this:
#include <iostream>
#include <vector>
using namespace std;
struct NODE
{
int data;
NODE * next;
};
NODE * removeAt(NODE * pList, int index)
{
if (!pList)
return nullptr;
NODE * temp = pList;
if (index == 0)
{
temp = pList->next;
std::cout << "removing " << pList->data << endl;
delete pList;
return temp;
}
// after this loop temp points to the node before
for (int i = 0; i < index -2; i++)
{
temp = temp->next;
if (!temp || !temp->next) // to guarantee both the-node-before and the-node-to-remove exist
return nullptr;
}
NODE * next = temp->next->next;
std::cout << "removing " << temp->next->data << endl;
delete temp->next;
temp->next = next;
return next;
}
int main()
{
std::vector<int> vec {15, 14, 13, 12, 11, 10};
NODE * root = nullptr;
for (const int v : vec)
{
std::cout << v << ' ' << endl;
NODE * cur = new NODE;
cur->data = v;
cur->next = root;
root = cur;
}
removeAt(root, 4);
return 0;
}
So my task is to take prewritten code that generates/populates/prints/ destroys a singly linked list and add functions that count the even number of nodes.
The specified prototypes are
int countEven(node * head)
compute and return the number of nodes that are in the linear linked list
int removeEven(node *& head)
remove all the nodes that contain an even number in the linear linked list and return the number of nodes removed
countEven was not a problem and is functioning correctly, however removeEven seems to work on random numbers
For example, main.cpp looks like so...
#include "list.h"
#include <iostream>
using namespace std;
int main()
{
node * head = NULL;
build(head);
display(head);
//PLEASE PUT YOUR CODE HERE to call the function assigned
cout << "The number of even nodes is " << countEven(head) << ".\n";
cout << "The number of even nodes removed was " << removeEven(head) << ".\n";
display(head);
destroy(head);
return 0;
}
and the function removeEven looks like so...
int removeEven(node *& head)
{
node *current;
node *trailCurrent;
int currentData = 0;
int numberOfItemsRemoved = 0;
current = head;
trailCurrent = NULL;
while(current != NULL)
{
currentData = current->data;
if(currentData % 2 == 0)
{
if (head == NULL)
cout << "Cannot delete from an empty list.\n";
else
{
if (head->data == currentData) //Node is in beginning of list
{
current = head;
head = head->next;
delete current;
numberOfItemsRemoved++;
}
else
{
trailCurrent->next = current->next;
delete current;
numberOfItemsRemoved++;
}
}
}
trailCurrent = current;
current = current->next;
}
return numberOfItemsRemoved;
}
The output is random since the build function seems to make random lists with random numbers but here is a sample
Here is the original list: 2 -> 51 -> 44 -> 46 -> 1 -> 49 -> 2 -> 53 -> 52 -> 2
This list contains 10 numbers of items
The number of even nodes is 6.
The number of even nodes removed was 6.
The resulting list is... 51 -> 31571024-> 1 -> 49 -> 53 -> 31571216
This list contains 6 number of items
The sum of all data is: 63142394
Valgrind is telling me there are invalid read and writes of size 8 which tells me that something is being written or read where it shouldn't. I don't think the case for a head node is the problem as the random number appears AFTER the first in the list, in which case I think the delete function is causing problems. Could anyone point out where I'm going wrong? I checked the other entries on deleting stuff from lists and my solution doesn't seem wrong. Thanks for the tips!
This is an example of a guiding principle that I follow, which is more often right than it is wrong: "when something looks too complicated, it's probably quite buggy".
This shouldn't be very complicated, with the right approach.
And the right approach, believe it or not, is not to try to keep the pointer to the current element being examined, but a pointer to the pointer to the current element, for the reasons that should become obvious:
int removeEven(node *& head)
{
node **currentptr= &head;
int numberOfItemsRemoved = 0;
while (*currentptr)
{
if ( (*currentptr)->data % 2) // Odd
{
currentptr = &(*currentptr)->next;
continue;
}
// Remove a node with an even value
node *p= *currentptr;
*currentptr= p->next;
delete p;
numberOfItemsRemoved++;
}
return numberOfItemsRemoved;
}
Fairly certain this will handle all edge cases. Multiple consecutive nodes to remove, removing the first node in the list, the last, etc...
I'm currently learning how to work with linked lists, specifically, doubly linked lists, and I have come across a problem with my program when I attempt to print it backwards.
Here is the portion of the code that I need help with:
#include <iostream>
using namespace std;
struct node
{
int data; //int to store data in the list
node *next; //pointer to next value in list
node *prev; //pointer to previous value in list
};
node *appendList(node *current, int newData) //Function to create new nodes in the list
{
node *newNode; //create a new node
newNode = new node;
newNode->data = newData; //Assign data to it
newNode->next = NULL; //At end of list so it points to NULL
newNode->prev = current; //Link new node to the previous value
current->next = newNode; //Link current to the new node
return newNode; //return the new node
}
node *createList(int maxLoop, node *begin, node *current, node *end) //Function to create list
{
//Allocate the starting node
current = new node;
current -> data = 1; //First data value is 1
current -> next = NULL; //next value is NULL
current -> prev = NULL; //previous value is NULL
begin = current; //This is the beginning of the list
for (int count = 2; count <= maxLoop; count++) //Loop to fill the list
{
current = appendList(current, count*count); //Create new nodes and fill with square numbers
}
end = current; //Now we are at the end of the list
return begin; //Return begin, this is the problem; I can't return end as well
}
void printForward (node *p) //Function to print the list forwards
{
node *curr = p; //current is the beginning value of the list
while (curr != NULL) //Continue while current is not at the end of the list
{
cout << curr->data << " "; //Print out the data of current
curr = curr->next; //Move one value along in the list
}
}
void printBackward (node *p) //Function to print the list backwards
{
node *curr = p; //current is the end value of the list
while (curr != NULL) //Continue while current is not at the beginning of the list
{
cout << curr->data << " "; //Print out the data of current
curr = curr->prev; //Move one value back in the list
}
}
int main()
{
//Initialize current, begin, and end
node *current = NULL;
node *begin = NULL;
node *end = NULL;
int maxLoop = 10; //The number of items in the list
cout << "The list has now been created." << endl;
begin = createList(maxLoop, begin, current, end); //function to create the list
cout << "Printed forwards, this list is: ";
printForward(begin); //Function to print the list forwards
cout << endl;
cout << "Printed backwards, this list is: ";
printBackward(end); //Function to print the list backwards
cout << endl;
return 0;
}
The purpose of this program is to create a list, print it forwards, backwards, insert an element, erase an element, and then destroy the list. I have chopped it down to just the create, print forward, and print backward functions.
The issue I have is that in the createList function I am modifying both begin and end but I can only return one or the other. This means that whichever I don't return is still NULL in the main function and therefore does not point to anything. I've tried setting the begin/current/end to not equal NULL but createList won't work if I do that.
Does anyone have any ideas for how I could modify both? Just to be clear, the list HAS TO be created in a function, it would be very easy to just initialize it in the main.
Thanks,
Tristan
Your problem is you're copying the pointers, when you should be passing them by reference, i.e., using a pointer-to-pointer or reference-to-pointer rather than just copying the value the pointer in main is originally pointing to. With what you're doing, you're unable to modify the original pointer variable that was declared in main ... passing-by-reference will allow you to-do that while also keeping all list setup code within your functions.
So for instance, change
node* createList(int maxLoop, node *begin, node *current, node *end)
to
void createList(int maxLoop, node** begin, node** current, node** end)
and then make sure to take the extra dereference into account in the body of your function
Finally, you would call it like:
createList(maxLoop, &begin, ¤t, &end);
And do the final assign to begin inside the body of the function of createList rather than in main.
I'm trying to wrap my head around how to write an algorithm to sort a linked list, but I'm having a hard time coming up with something that will work. What we need to do have a linked list that contains a name in a string, and an int for hours. After displaying the list and the sum of the hours, we then have to sort the list in ascending order by the hours in a queue. I have the list and all it's functioned stored in a class object, as you will see. I cleared the whole function of what I had in hopes of coming up with a fresh idea but nothing is coming to mind. I initially was going to create a second linked list that had the sorted list, but then I began to wonder if it was possible to sort it within the same list. Here is my code as of posting.
#include <iostream>
#include <ctime>
using namespace std;
// OrderedLL class
template<class T>
class OrderedLL
{
private:
struct NODE
{
string sName;
int sHours;
NODE *next;
};
NODE *list;
NODE *rear;
public:
// Constructor
OrderedLL () { list = rear = NULL;}
// Insert item x -------------------------------------
void Insert(string x, int y)
{
NODE *r;
// Create a new node
r = new(NODE); r->sName = x; r->sHours = y;
r->next = NULL;
// Inserts the item into the list
r->next = list;
list = r;
}
// Display the linked list --------------------------
void display()
{ NODE *p = list;
while( p != NULL)
{ cout << p->sName << "/" << p->sHours << "-->"; p = p->next;}
cout << "NULL\n";
}
// Delete x from the linked list --------------------
void DeleteNode(T x)
{
NODE *p = list, *r = list;
while( p->info != x) {r=p; p=p->next; }
if( p == list)
{ // delete the first node
list = p->next; delete(p);
}
else
{ r->next = p->next; delete(p);}
}
// Sort by hours ------------------------------------
void sortHours()
{
NODE *p, *q;
}
// Display the total hours --------------------------
friend T totHours(OrderedLL LL)
{
NODE *p;
int total = 0;
p = LL.list;
while(p != NULL)
{
total += p->sHours;
p = p->next;
}
cout << "Total spending time = " << total << endl;
}
}; // end of OrderedLL class
int main(void)
{
// Declare variables
time_t a;
OrderedLL<int> unsortedLL;
OrderedLL<int> sortedLL;
int inHours;
string inName;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
// Asks the user to enter a name and hours 5 times, inserting each entry
// into the queue
for(int i = 0; i < 5; i++)
{
cout << "Enter name and Time: ";
cin >> inName >> inHours;
unsortedLL.Insert(inName, inHours);
}
// Displays the unsorted list
cout << "\nWaiting List-->";
unsortedLL.display();
totHours(unsortedLL);
// Calls for the function to sort the list into a queue by hours
unsortedLL.sortHours();
unsortedLL.display();
return 0;
} // End of "main"
As always thanks to anyone who can help
Try sorting the linked-list like you are sorting an integer array. Instead of swapping the nodes, swap the contents inside the nodes.
If you don't care about efficiency you can use any sorting algorithm. What's different between linked lists and arrays is that the swap operation, to swap the position of two elements while sorting, will be a lot slower because it has to run through the links of the list.
An O(n²) bubble sort is easy to implement with a linked list since it only swaps an element with its neighbor.
If you care about efficiency you can look into implementing the merge sort algorithm even if it's a little more complicated.
You should insert like this
void Insert(string x, int y)
{
NODE *r;NODE *temp;
// Create a new node
r = new NODE; r->sName = x; r->sHours = y;r->next = NULL;
if(list==null)//check if list is empty
{
list=r;//insert the node r in the list
}
else
{
temp=list;
while(temp->next!=null)temp=temp->next;//reach to the end of the list
temp->next=r;//insert it at the end of the list
}
}
No need of rear pointer..just check if list->next is null,if yes you are at the end
and your sorthour function should be
void sortHours()
{
for(NODE* n=list;n->next!=null;n=n->next)//get each of the node in list 1 by 1 except the last one i.e. n
{
for(NODE* n1=n->next;n1!=null;n1=n1->next)//compare the list n node with all the nodes that follow it i.e.n1
{
if(n->sHours > n1->sHours)//if one of the node is the less than n
{
//swap n and n1
node temp=*n;
n->age=n1->age;
n->name=n1->name;
n1->age=temp.age;
n1->name=temp.name;
}
}
}
}