Inserting a node in nth position in a linked list - c++

#include<iostream>
using namespace std;
struct node {
int data;
node *link;
};
node *head = NULL;
void insert(int data, int n)
{
node *temp = new node();
temp->data = data;
if (n == 1)
{
temp->link = head;
head = temp;
}
else
{
node* ptr = head;
for (int i = 1; i <= n - 1; i++)
ptr = ptr->link;
temp->link = ptr->link;
ptr->link = temp;
}
}
void print()
{
cout << "list is: ";
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->link;
}
cout << endl;
}
int main()
{
insert(2, 1);
insert(3, 2);
insert(4, 3);
insert(5, 4);
insert(6, 5);
print();
return 0;
}
This is a code to implement insertion in a linked list at nth position. The data and position are being passed from the main position.
I am not getting what is the possible error I have made, it has something to do with the for loop.
Its not executing, however if i make the following change:
for(int i=0;i<n-2;i++)
it works fine.

First insert(2,1) works fine. So you have linked list like this
(2)->NULL
|
head
In the second insert, Lets follow the code,
1. else
2. {
3. node* ptr = head;
4. for (int i = 1; i <= n - 1; i++)
5. ptr = ptr->link;
6. temp->link = ptr->link;
7. ptr->link = temp;
8. }
Line 3, ptr points to head. n is 2
(2)->NULL
|
head
|
ptr
Line 4, 1 <= (2-1) is true because 1 == 1, so for loop runs once
Line 5, ptr moves one step, so it points to NULL
(2)->NULL
| |
head |
|
ptr
Line 6, ptr->link is called, which is NULL->link. So it crashes here.
When you do for(int i=0;i<n-2;i++), n is 2, so 0 < (2-2) is false, so it runs fine. Note: Works only when insert calls are made in order like your example. If they are called in wrong order, it wont work.
Changing Line 6 to temp->link = ptr;, should also work without changing the loop.

"Inserting a node in nth position in a linked list" :
Use a std::list rather than rolling your own. Then use std::list::insert.
Also; consider just using a std:: vector instead. A list is a terrible (pointer chasing, cache miss inducing) data structure to use on modern CPUs. A std::vector will almost always beat it (regardless of what your textbooks say about theoretical performance).

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'.

Linked List: issues finding index of node to remove at [index not incrementing correctly]

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

Returning a pointer to certain point of circular linked list

I'm working on circular doubly linked list. For example I have three values in it
1 2 3
and I'm passing it into method where I insert 0 in the middle, like that:
1 0 2 3
I wonder if it's possible somehow to return it back, but with pointer's moved to this 0 value instead of standard start on 1 value? If not, how would you do an 'actual position' pointer to this list, which shows where nodes were deleted/inserted?
//Edit
There I'm adding my code
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int allCharCounter = 0;
struct List_node{
int value;
struct List_node *next;
struct List_node *prev;
};
void insert(List_node** start, int v){
List_node* newNode = new List_node;
newNode->value = v;
if(*start == NULL){
newNode->next = newNode;
newNode->prev = newNode;
*start = newNode;
}else{
newNode->next = *start;
newNode->prev = (*start)->prev;
(*start)->prev->next = newNode;
(*start)->prev = newNode;
}
}
//This method should insert a node after node where the pointer was
//With value smaller by 1 -> (c-1)
//after insertion pointer should be moved 'c' times
void insertAndMove(List_node** POS){
if((*POS)->next = NULL){
return;
}else{
int c = (*POS)->value;
//cout << c << endl;
List_node* newNode = new List_node;
newNode->value = c-1;
(*POS)->next = newNode;
newNode->prev = *POS;
newNode->next = (*POS)->next;
(*POS)->next->prev = newNode;
//List_node* current;
//there I planned to move my list
for(int i = 0; i < c; i++){
//*POS = (*POS)->next;
//cout <<"POS: " << (*POS)->value << endl;
}
}
}
int getNumber(){
int c = getchar();
int value = 0;
for(; (c < 48 || c > 57); c = getchar());
for(; c > 47 && c < 58 ; c = getchar()){
value = 10*value+c-'0';
allCharCounter++;
}
return value;
}
int main(){
int numberOfOperations = getNumber();
struct List_node* list = NULL;
while(!feof(stdin)){
int number = getNumber();
insert(&list, number);
}
insertAndMove(&list);
cout << list->value << endl;
}
I'm sorry if I don't described the problem and assumptions clearly. I have already asked a question where I vastly desribe it. There should be better overview what I want to achieve:
Self-organising sequence of numbers with big amount of operations on it - best data structure
If it is circular doubly linked list, then you can just move all the elements before the inserted element to end of the list [a1,a2,a3,a4] -> [a1,a2,new,a3,a4]->[new,a3,a4,a1,a2]
The pointer will be at new but it still is the same list.
I hope it'll be helpful
It would be easy enough to have your list head be a pointer-to-pointer and set that to your new list head. The thing to keep in mind with a circular list is that you need to keep track of some starting point so you know when you have gone through the entire list, but that starting point does not itself need to be stable so long as you are aware that it can change.

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;

How to display all list values without endless loop

I have a list and I want to display it's values.
I want to see 1 2 3 4, but I have a endless loop like 1 2 3 4 1 2 3 4 1 2..
Can't understand, why?
struct node
{
int item;
node *next;
node(int x, node *t)
{
item = x;
next = t;
}
};
int main()
{
node *firstElement = new node(1, NULL);
firstElement->next = firstElement;
node *lastElement = firstElement;
for (int i = 2; i < 5; i++)
lastElement = (lastElement->next = new node(i, firstElement));
for (node *first = lastElement; first != 0; first = first->next)
cout << first->item << " ";
delete firstElement;
return 0;
}
Try using this code:
struct node
{
int item;
node *next;
node(int x, node *t)
{
item = x;
next = t;
}
};
int main()
{
node *firstElement = new node(1, NULL);
node *lastElement = firstElement;
for (int i = 2; i < 5; i++)
lastElement = (lastElement->next = new node(i, nullptr));
for (node *first = firstElement; first != 0; first = first->next)
cout << first->item << " ";
return 0;
}
IdeOne live code
The problem is that you set the "next" link of your last node to this node itself, not nullptr.
Also, it's better to delete the memory allocated
The problem is that your data structure has an infinite loop in itself: this line
firstElement->next = firstElement;
makes firstElement point back to itself, creating a circular list. When you add more elements, your list remains circular, so exit condition first == 0 is never achieved.
If you want your list to remain linear, not circular, your insertion code should be modified as follows:
node *firstElement = new node(1, NULL);
node *lastElement = firstElement;
for (int i = 2; i < 5; i++) {
lastElement->next = new node(i, lastElement->next)
lastElement = lastElement->next;
}
The printing code should start with firstElement:
for (node *current = firstElement; current != 0; current = current->next)
cout << current->item << " ";
Finally, deleting a single firstItem is not sufficient. You need a loop to traverse the whole list. Alternatively, you could chain deletion in the destructor by calling delete next, but this is dangerous, because recursive invocation of destructors may overflow the stack.
You have a loop in your list, because lastElement->next always points to firstElement. This is why first will never be equal to 0.
If you really need a loop I think you should write something like this:
node* p = firstElement;
do {
cout << p->item << " ";
p = p->next;
} while (p != firstElement);
The problem is that you create every node with firstElement as its next.
This would make sense if you were adding nodes to the front of the list, but you're adding them at the back, so the last node will point back to the start.
Since you're adding to the back, terminate the list on every insertion instead:
lastElement->next = new node(i, nullptr))