While loop with pointers does not work - c++

I have a problem, I am trying to create a list that deletes a highest value holding number, or all numbers with the same value if the value is highest in the list. Thank you for any kind of tips.
// n,n1,head,next - are pointers
int j = 0; //this number helps to put pointer forward by one place
while(n!=0){//should go through every digit of the list
if(head == 0){
cout << "list is empty" << endl;
}
else{
n = head;
n1=0; // n1 and n are pointers
while(n!=0){
if(n->sk == maxx){//searches for maximum digit in the list
break;
}
else{
n1=n;
n=n->next;
}
}
if(head == n){
head = head->next;
}
else{
n1->next = n->next;
}
delete n; // deletes the pointer holding the highest value
}
n = head; //problem is here or somewhere below
j++;
for(int i=0; i<j;i++){ // this loop should make the pointer point to the first
n = n->next; // number, then the second and so on until the end of list
} // and all the numbers inside the list with the value that
} // equals "maxx" should be deleted

You should dereference the pointers. Right now, you're pointing to their addresses. See if that helps resolve your problem.

Ok, the problem (the most of it) is the code:
while(n!=0){
if(n->sk == maxx){
break;
}
else{
n1=n;
n=n->next;
}
}
If you find the maxx value you should delete that node and continue to searching, don't break. This way you don't need so much code for this task.
while (n != 0){
if (n->sk == maxx){
node *prev = n->prev; // The previous node.
node *tmp = n; // this assume you have a class node.
// temporaly holds the pointer to n.
prev->next = n->next; // Connect the previous node with the following one.
n = n->next; // advance n to the next node in the list.
delete tmp; // delete the node.
}
}

If I understand correctly what you want, you can just iterate over your list and save the pointer for deletion:
it = head;
pos = nullptr;
while (it != nullptr) {
if(it -> sk == maxx) {
pos = it; // save ptr
it = it -> next;
delete pos; // delete saved ptr
pos = nullptr;
}
}

Related

Sieve of Eratosthenes C++ using single linked list

Hi I have a problem with Sieve of Eratosthenes in C++. I have to do this using single linked list. My program is running and showing first declaration of list but I don't know how to delete non prime numbers properly. My function just isn't working for me. How should I change my delete function?
#include <iostream>
#include <cmath>
using namespace std;
struct List
{
int number;
List* next;
};
List* head = new List;
void l_add(int n)
{
List* temp = head;
for (int i = 2; i <= n; i++)
{
temp->next = new List();
temp->number = i;
temp = temp->next;
}
}
void l_print()
{
List* temp = head;
while (temp->next != 0)
{
cout << temp->number << " ";
temp = temp->next;
}
cout << endl;
}
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
if (temp->number % i == 0)
{
head = temp->next;
delete temp;
temp = head;
}
while (temp->next != 0)
{
if (temp->next->number % i == 0)
{
temp->next = temp->next->next;
delete temp->next;
}
temp = temp->next;
}
}
}
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
cin >> n;
l_add(n);
l_print();
l_delete(n);
l_print();
return 0;
}
This would be a working version of the l_delete method:
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
while (temp->next != 0)
{
if (temp->next->number % i == 0 && temp->next->number != i)
{
List* temp2 = temp->next->next;
delete temp->next;
temp->next = temp2;
}
if(temp->next == 0) break;
temp = temp->next;
}
temp = head;
if (temp->number % i == 0 && temp->number != i)
{
head = temp->next;
delete temp;
temp = head;
}
}
}
There were several problems with your deletion method.
Problems with algorithm logic: With your algorithm head should be checked last because otherwise if its deleted, the new head is not checked for primality, you immediately check new next, which is old ->next->next. Also you didn't check if number is equal to divider in which case it should not be deleted.
Problems with programming logic:
When you're deleting next node in the while loop, same as when deleting head, you need another temporary variable to store temp->next->next and then after deleting assign it to temp->next.
But the biggest problem here is that this is not Eratosthenes sieve at all, you are
just checking all numbers for divisibility with all others smaller than sqrt(n). It
is suboptimal compared to the Eratosthenes sieve. If you Google Eratosthenes sieve, you’ll find a lot of detailed tutorials and explanations.
I like what Bran is pitching, and I'm going to add a few tricks.
Comment: Global variables suck. They make things harder to trace when projects get bigger. I'd move head into main and pass it around as a parameter. I'm also ditching the sentry node because I find them more trouble than they are worth most of the time.
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
if (cin >> n)
{
// should be a bit more logic here to automatically handle ns of 1 or 2
List* head = nullptr; // not using a sentinel node
l_add(head, n); // passing in head rather than global variable free-for-all
l_delete(head);
l_print(head);
return 0;
}
else
{
cout << "invalid input." << endl;
return 1;
}
}
When adding to the linked list, you don't need any even numbers other than 2. So don't add them. Less time spent iterating the list. After that it's a matter of making sure nodes go in in the right order.
void l_add(List*& head, // passing in head. Easier to track
int n)
{
List** temp = &head; // head is a next pointer with a different name
// hiding it behind another pointer allows us to treat
// it like a next
// temp is now a pointer to next pointers. We can add directly to the
// last nodes's next pointer and also use it to access the current
// pointer if we need to
(*temp) = new List {2, nullptr}; // 2 is only even prime
temp = &(*temp)->next;
for (int i = 3; i <= n; i+=2) // start at 3 and only add odd numbers
{
(*temp) = new List {i, nullptr};
temp = &(*temp)->next; // Advance to next node
}
}
When we're iterating through the list looking to eliminate multiples we need two loops. One to keep track of the node we're eliminating multiples and another loop to do the hunting and eliminating. Note that I'm using the pointer-to-pointer trick again. This trick annihilates about half of the code needed to traverse and remove nodes.
void l_delete(List * head)
{
List* last = head->next; // track the last known prime node. skip node 2.
// note this will blow up if there is no node 2.
while (last) // for every node still in the list
{
List** current = &last->next; // similar to trick above.
// if we have a pointer to the next to be
// updated, we don't need to track the previous node
while ((*current)) // look at every node after the last prime
{
if ((*current)->number % last->number == 0) // if it's a multiple, remove it.
{
List * to_del = (*current); //save node to delete
(*current) = (*current)->next; // link previous node to next node.
// effectively automatically advances the node
delete to_del;
}
else // proceed to next node
{
current = &(*current)->next;
}
}
last = last->next; // advance to next prime number
}
}
Probably plenty of room in there for optimization, but I'm aiming more for readability because if I drop ten lines of cryptic gibberish nobody learns nuthin'.

How can I check each 3 elements of a singly linked list and then delete some of them?

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. :)

How to delete element next to the highest found element in the circular list in C++

I've got a problem with some function/algorithm, and I hope you guys can help me. The task is to write a function that will delete an element that is right after the hightest element(highest value) in single linked circular list. I've been trying to draw this so this would make more sense to me, but it still looks like dark arts, but i've managed to come up with a function like this:
struct node
{
node * next;
double data;
};
void Insert_node(node * & head, double v)
{
node * p = new node;
p->data = v;
if(head)
{
p->next = head->next;
head->next = p;
}
else p->next = p;
head = p;
}
void Delete_After_Max(node* & head)
{
node * tmp=head;
int counter=0,index=0;
double maximum=0;
if(tmp) // checking if the list is not empty
{
do
{
if(tmp->data>maximum)
{
maximum=tmp->data;
index=counter+1;
}
counter++;
tmp=tmp->next;
} while(tmp!=head);
}
cout<<"Biggest value on the list: "<<maximum<<endl;
cout<<"licznik:"<<counter<<" "<<"indeks: "<<index<<endl;
if(counter==(index+1))
index=0; //if last element is the maximum, first one will be deleted
else
index++; // incrementing to get index of the next element after maximum
node *tmp2=NULL;
//checking if the highest element was last(then we delete first one)
if(index==0)
{
index=counter;
}
// checking if the highest element was somewhere else
node *tmp3=NULL;
int position=0;
if((index>0)&& (index<=counter))
{
tmp2=head;
while(position<index-1)
{
tmp2=tmp2->next;
position++;
}
tmp3=tmp2->next;
tmp2->next=tmp3->next;
if(head==tmp3)
{
head=head->next;
}
delete tmp3;
}
}
Do you think this algorithm is right? I'm not sure if I get the idea right, so the code is probably totally wrong :/
At first, I count all the elements on the list, find the highest one and it's index, and then I can use it to delete element after that by incrementing the index, right? I think that it's ok to this moment, but after that it gets harder to me, if the maximum was last element, i have to delete the first one, and "connect" the last one with the second one? But I don't know if it's ok with circular list, so please, can someone give me a hint what I'am doing wrong? ;)
I checked it again, and it compiles but it's not working properly, and I still don't know why, and how to do it. I couldn't find any similar problems that I could base on, any kind of help would be appreciated, I'am new to this, that's why there are so many mistakes...
In the proposed algorithm, small errors are doing a wrong result.
Error 1 - the biggest, in the last while-loop the tmp2 is not initialized.
Initialize tmp2 = head instead of tmp3 = head;.
tmp2 = head; // initialize tmp2
while (position<index - 1)
{
tmp2 = tmp2->next;
position++;
}
tmp3 = tmp2->next;
Error 2 - starting with position equal 1 will stop the loop too early.
Using first position = 1 with the while-condition (position < index
- 1) decrease the loop by 2 steps.
int position = 0;
Typo Error - in the if (index == 0) condition, a missing semi-column.
The line code head = head->next doesn't end by ;.
In the condition if (index == 0) either exiting from the function with return or prevent doing unexpected operation by inserting the last part in a else { ... } condition.
if (index == 0)
{
tmp2 = head;
head = head->next;
delete tmp2;
// EXIT by return
}
ADDED N°1>>>>
Error 3 - the case if (index == 0) is not possible
Try to delete the first node of the circular linked-list when the
maximum is placed in the last node is not possible.
The value index = 0; is possible only when if (counter == index). But in the do-while, just after storing the position of the maximum in index = counter; the counter is incremented counter++;.
Modify as follow:
if (counter == (index+1)) // detecting the last position
index = 0; //if last element is the maximum, first one will be deleted
else
index++; // incrementing to get index of the next element after maximum
But to delete the first node, the proposed algorithm for if (index == 0) doesn't work because it is necessary to store the previous node.
Solution - The best solution is to force the last while-loop to continue one step more by doing the following changes:
if (index == 0)
{
index = counter;
}
Then allow the while-loop when (index == counter) with:
if ((index>0) && (index<=counter)) // allow for the last
{
tmp2 = head;
while (position<index - 1)
And before the deletion of the tmp3 node, modify the head when tmp3 == head:
tmp3 = tmp2->next;
tmp2->next = tmp3->next;
if (head==tmp3) { // when the node to delete is the head
head = head->next; // shift head to the next node
}
delete tmp3;
ADDED N°2>>>>
Output - here is the obtain result when using the suggested list of values.
The first element 6 is the deleted (next element of the last element
18 in a circular linked-list).
[ 6, 9, 13, 12, 1, 10, 15, 4, 6, 18, ].
Biggest value on the list: 18
[ 9, 13, 12, 1, 10, 15, 4, 6, 18, ].
ADDED N°3>>>>
Here is the full source code of the function Delete_After_Max():
void Delete_After_Max(node* & head)
{
node * tmp = head;
int counter = 0, index = 0;
double maximum = -1;
if (tmp) // checking if the list is not empty
{
do
{
if (tmp->data>maximum)
{
maximum = tmp->data;
index = counter;
}
counter++;
tmp = tmp->next;
} while (tmp != head);
}
std::cout << "Biggest value on the list: " << maximum << "\n";
if (counter == (index+1))
index = 0; //if last element is the maximum, first one will be deleted
else
index++; // incrementing to get index of the next element after maximum
node *tmp2 = NULL;
//checking if the highest element was last(then we delete first one)
if (index == 0)
{
tmp2 = head;
std::cout << tmp2->data << ", ";
index = counter;
//head = head->next;
//delete tmp2;
// EXIT
}
// checking if the highest element was somewhere else
node *tmp3 = NULL;
int position = 0; // ERROR 1;
// if ((index>0) && (index<counter))
if ((index>0) && (index<=counter))
{
// ERROR tmp3 = head;
tmp2 = head;
while (position<index - 1)
{
tmp2 = tmp2->next;
position++;
}
tmp3 = tmp2->next;
tmp2->next = tmp3->next;
if (head==tmp3) {
head = head->next;
}
delete tmp3;
}
}
ADDED N°4>>>>
In the updated function Delete_After_Max() displayed bellow the logical to delete the node following the maximum is wrong.
bool Delete_After_Max(node* & head)
{
node *maxi=Find_Maximum(head);
std::cout << "Biggest value on the list: " << maxi->data << "\n";
if(!Is_Empty) // !Is_Empty because this function is not working properly so i had to negate it until i find out why ;)
{
cout<<"the list is empty";
return false;
}
else
{
node *tmp3=NULL;
node *tmp2=maxi->next;
tmp3=tmp2->next;
tmp2->next=tmp3->next;
if (head==tmp3) {
head = head->next;
}
delete tmp3;
cout<<"one element deleted";
return true;
}
}
If maxi is pointing to the node having the maximum value, the node to be delete is maxi->next (instead of calling tmp2 we will call it node_to_delete).
Before deleting the node_to_delete, it is necessary to connect the node maxi with the node following the node_to_delete (instead of calling tmp3 we will call it node_after_delete).
In case of the node_to_delete is the head, it is necessary to update the head with its next node before deletion.
Then, the new deletion part of the function becomes:
// Step 1
node *node_to_delete = maxi->next;
// Step 2
node *node_after_delete = node_to_delete->next;
maxi->next = node_after_delete;
// Step 3
if (node_to_delete == head) {
head = head->next;
}
delete node_to_delete;
So, logic errors in the function Delete_After_Max() are:
Bad connection between the node maxi and the node node_after_delete (tmp3) ==> maxi->next=tmp3; instead of tmp2->next=tmp3->next;,
Bad definition of the node node_to_delete (tmp2) ==> if (head==tmp2) and delete tmp2; instead of if (head==tmp3) and delete tmp3;

Deallocating memory from a linked list

I'm trying to delete the n'th element, which is a random number from 1 to n.
My code does this fine (correct element is deleted and surrounding elemnts are connected) but when it comes to being efficient, it is crashing when I un-comment the line delete (nodeToRemove); and I'm not sure why. Does anyone have any insight?
Assuming my struct looks like :
struct Node {
int data; // The data being stored at the node
Node *next; // Pointer to the next node
};
//------------------------------------------------------------------------------
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
head = head->next;
}
else
{
for (int i = 1; i < random - 1; i++)
temp = temp->next;
nodeToRemove = temp->next;
temp->next = temp->next->next;
}
// delete (nodeToRemove); <----- uncommenting this leads to crash,
}//end deleteNthElement()
//------------------------------------------
int main()
{
Node *head = NULL;
Node *temp;
Node *listarray[n[i]];
int n[] = {1000, 5000, 9000, 105000, 400000, 500000, 505000, 800000, 995000, 1000000};
for (int j = 0; j < n[i]; j++)
listarray[j] = new (Node);
//start timer
begin = clock();
//fill it
for (int j = 0; j < n[i]; j++)
{
listarray[j]->data = (rand() % n[i] + 1);
insertNodeInOrder (head, temp, listarray[j]);
}
//delete it
for (int j = 0; j < n[i]; j++)
deleteNthElement (head, temp, (rand() % (n[i] - j) + 1));
//deallocate
for (int j = 0; j < n[i]; j++)
delete listarray[j];
delete *listarray;
//end timer
}
You're picking the wrong Node, you want:
...
nodeToRemove = temp;
...
At least, you have to check for the end of the list, that is, you need to avoid access to null pointers (i really hope you set next to 0 at the end of the list). If you add the allocation parts, I will extend my answer.
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
if(head != 0)
head = head->next;
} else {
for (int i = 1; i < random - 1; i++)
if(temp != 0)
temp = temp->next;
else throw 1; // no such index; throw something more verbose :)
if(temp == 0)
throw 1; // same situation as above
nodeToRemove = temp->next;
if(nodeToRemove == 0)
throw 1; // same situation as above
temp->next = temp->next->next;
}
if(nodeToRemove == 0)
throw 1; //no such index; ... as the above 3
delete nodeToRemove;
}//end deleteNthElement()
Some clean-up first:
Why pass in two pointers here? do you need the value of temp out? If so why not return it?
Also why the node * & temp? (I can see why it is done for head).
int random should probably be called something like index as it describes the functionality better (as far as the function is concerned, there is nothing random about it).
The same with temp.
I propose:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
//...
We don't need temp if we are removing the head. Also, we generally 0 index things, so we should reflect that too. Thus it becomes:
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
Now we get to the main bit. The loop is just there to step through to the parent node of the node to delete, so we can simplify it a little and add checks to make sure we can't 'fall off' the end of the list.
We then have to make sure there is a node to remove, (so another check). We don't need to check for a node beyond as assigning nullptr isn't a problem (I am assuming that an invalid pointer is set to nullptr here):
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
Incidentally, this fixes a probable off by one error. Which is probably your problem (did it crash every time? only when deleting the last element? next to last?
Now we just need to delete it.
Putting it all together:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
else
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
delete node_to_remove;
return;
}
And that should work fine. The checks will prevent us dereferencing null pointers which was (probably) what caused you to crash. Can't tell without full code.

Bubble sorting for linked list

I am trying to sort a singly linked list using bubble sort. If there is a simple mistake then please pardon. Please tell me where I am going wrong. Program stops unexpectedly when I try to do this.
void sortBubble()
{
Node *i=start,*j=start;Node *temp;Node* prev=start;Node* agla;
while(i->next!=NULL)
{
cout<<"\nhello 1";
j=i;
agla=j->next;
while(agla!=NULL)
{
temp=NULL;temp->next=NULL;
cout<<"\nhello2";
if(*(j) > *(agla))
{
temp=agla->next;
agla->next=j;
prev->next=agla;
prev=agla;
agla=j->next;
j->next=temp;
}
else{
prev=j;
j=agla;
agla=j->next;}
}
prev=i;
i=i->next;
}
}
}
Your first obvious mistake that absolutely leads to program crash is:
while(agla!=NULL)
{
temp=NULL;temp->next=NULL;
You are setting a variable to NULL, then setting its fields. A null pointer points to nowhere, so you cannot edit its contents.
Remove temp->next=NULL;
Edit:
Your program logic is not correct. You ruin the list after a few iterations of the loop and the program sticks in an infinite loop with mixed up pointers.
In bubble sort, we iterate through the items several times. In each iteration, the largest item is bubbled up to the end of the list. After first iteration, we are sure that the largest element is at the end of the list. After second iteration, we are sure that the second largest element is before the last element of the list, and so on.
You repeat this process until all the items are on their places:
int getListSize(Node* start)
{
int count = 0;
while(start != NULL)
{
count++;
start = start->next;
}
return count;
}
void bubbleSort(Node *&start) // <-- Pass a reference to pointer, because we may need to modify the start pointer.
{
int size = getListSize(start);
int i = 0;
while(size--)
{
Node
*current = start,
*prev = NULL; // We are at the beginnig, so there is no previous node.
while(current->next != NULL) // We have at least one node (size > 0) so `current` itself is not NULL.
{
Node *after = current->next;
if((*current) > (*after))
{
//swap the items
current->next = after->next;
after->next = current;
if (prev == NULL) // we are at the beginning
start = after;
else
prev->next = after;
prev = after;
}
else
{
prev = current;
current = current->next;
}
}
}
}
We repeat the "bubbling up" process size times. This is not the most efficient way, since we even compare the items that are already sorted. A more efficient way is to sort until no new swapping occurs:
void bubbleSort(Node *&start) // <-- Pass a reference to pointer, because we may need to modify the start pointer.
{
int size = getListSize(start);
int i = 0;
Node *lastSwapped = NULL;
while(size--)
{
Node
*current = start,
*prev = NULL, // We are at the beginnig, so there is no previous node.
*currentSwapped = NULL;
while(current->next != lastSwapped) // We have at least one node (size > 0) so `current` itself is not NULL.
{
Node *after = current->next;
if((*current) > (*after))
{
//swap the items
current->next = after->next;
after->next = current;
if (prev == NULL) // we are at the beginning
start = after;
else
prev->next = after;
prev = after;
currentSwapped = current;
}
else
{
prev = current;
current = current->next;
}
}
if (currentSwapped == NULL)
break; // No swapping occured. The items are sorted.
else
lastSwapped = currentSwapped;
}
}
This is the complete working program
You are comparing the elements by simply doing *(j) > *(agla), I'm not sure how that builds since both j and agla are pointers to structures. Structures cannot be compared directly.