singly linked list insertion issue - c++

I was trying to insert element at end of a linked list, but if I comment the break in my while loop, it goes to a continuous loop, I'm unable to figure out why
code:
head=NULL;
node *temp=head;
for(int i=0;i<5;i++)
{
//temp=head;
node* t1=new node;
if(head==NULL)
{
t1->a=i;
t1->next=NULL;
head=t1;
}
else
{
temp=head;
while(temp!=NULL)
{
if(temp->next==NULL)
{
t1->a=i;
t1->next=NULL;
temp->next=t1;
//break;
}
temp=temp->next;
}
}
}
temp=head;
while(temp!=NULL)
{
cout<<temp->a<<endl;
temp=temp->next;
}

Your while loop is trying to traverse the new node you have just added again and again. Breaking the loop after the insert operation is correct here, otherwise the while loop may loop indefinitely.

Your while loop runs forever without the break because temp is never set to NULL to stop the loop. When the while loop reaches the last node in the list, it appends the new node to the end, then sets temp to that node. So the next loop iteration sees that node, appends again, and again, and again, endlessly.
So, you need to break the while loop when the last node has been reached:
for(int i = 0; i < 5; i++)
{
node* t1 = new node;
t1->a = i;
t1->next = NULL;
if (head == NULL)
{
head = t1;
}
else
{
node *temp = head;
while (temp != NULL)
{
if (temp->next == NULL)
{
temp->next = t1;
break;
}
temp = temp->next;
}
}
}
In which case, the while loop can be simplified to not need break at all:
for(int i = 0; i < 5; i++)
{
node* t1 = new node;
t1->a = i;
t1->next = NULL;
if (head == NULL)
{
head = t1;
}
else
{
node *temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = t1;
}
}
That being said, this whole code can be greatly simplified further, to not reiterate the entire list on each iteration of the outer for loop, and to not use an if.. else to decide whether or not to set the head:
node **temp = &head;
while (*temp != NULL)
{
temp = &((*temp)->next);
}
for(int i = 0; i < 5; i++)
{
node* t1 = new node;
t1->a = i;
t1->next = NULL;
*temp = t1;
temp = &(t1->next);
}

Related

Printing the singly linked list

I am a newbie to programming
Here I wrote a code for accepting and displaying the values using linked list.
However the code takes all the values but displays only the last value
Here is the code
#include <iostream>
using namespace std;
struct node {
int value;
node* next;
};
class llist {
public:
void create();
void display();
node* head = NULL;
};
void llist::create()
{
struct node* temp;
temp = NULL;
struct node* p;
p = new struct node;
cin >> p->value;
if (head == NULL) {
head = p;
}
else {
temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->value = p->value;
temp->next = NULL;
}
}
void llist::display()
{
struct node* temp = head;
while (temp != NULL) {
cout << "VALUE:" << temp->value << endl;
temp = temp->next;
}
}
int main()
{
int n, i;
llist l1;
cin >> n;
for (i = 0; i < n; i++)
l1.create();
cout << "Displaying list\n";
l1.display();
return 0;
}
Input:
4
1
2
3
4
Displaying list
VALUE:4
I am wondering what went wrong...
Change this:
else {
temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->value = p->value;
temp->next = NULL;
}
to this:
else {
temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = p;
}
When inserting a new element at the end of a linked list, you find the last element inside the while loop and put it in the temp variable. Then you assign its next value to your new p element. The way you were doing before, you were just overriding the integer number of the last element. That is why when you printed your list you only got the last number you entered.
Also, when creating a new element p, be sure to initialize its next value to NULL:
p = new struct node;
p->next = NULL;
Problem is with the last 2 lines in the else block.
You are overwriting the value and maintaining just the single mode in your list class. And that's the reason, only last value is displayed.
Replace
temp->value = p->value;
temp->next = NULL;
With
temp->next = p;

Sorting the linked list during insert

So I'm trying to insert nodes into linked list in descending order, but I struggle when I'm getting duplicate numbers and cant find a good solution for the problem. I either encounter missing numbers / program crash or program lists only 1 number infinite times.
Here is my code that I think works up to the "else" statement, it's the part that I cant figure out and im just leaving my last version, which doesnt work obviously
void Link::insert(int number) {
Node *news = new Node;
news->number = number;
if(first == NULL) {
first = news;
}
if(news->number > first->number) {
Node *temp = first;
first = news;
news->next = temp;
} else {
Node *temp = first;
while (temp->next || news->number < temp->number) {
temp=temp->next;
}
temp->next = news;
news->next = temp->next;
}
}
If the other functions are needed or my main.cpp please let me know.
Maybe
void Link::insert(int number){
Node *news = new Node;
news->number = number;
if(first == NULL){
first = news;
return;
}
for(Node *i=first, *pred=NULL;!i;i=i->next){
if(i->number<number){
if(i==first) {
news->next=first;
first=news;
} else {
pred->next=news;
news->next=i;
}
break;
}
pred=i;
}
}
When you are first inserting, it goes into your first if condition and then sets first=news, but after that its again checking news->number > first->number which will be false, so going into the else condition unnecessarily. So either add return; in first if block or put others in else block.
keep track of previous element
else{
Node *temp=first,*prev=null;
while (temp && (temp->next || news->number < temp->number)){
prev=temp;
temp=temp->next;
}
if(prev==null){
news->next=first;first=news;
}
else{
prev->next=news;news->next=temp;
}
}
You should swap your 2 last lines, else you have news->next = news, creating a cycle.
Anyway, I suggest to split the function in 2 (private) parts: One which found the Node* where to insert after (or nullptr for first position), and the method for the insertion (and it is so easier to debug).
Node* Link::upper_bound(int value) const
{
if (first == nullptr || first->number <= value) {
return nullptr;
}
Node* node = first;
Node* next = first->next;
while (next && value < next->number) {
node = next;
next = node->next;
}
return node; // we have: node->number < value && (next == nullptr || value <= next->number)
}
void Link::insert_after(Node* node, int value)
{
Node* new_node = new Node(value);
if (node == nullptr) {
new_node->next = first;
first = new_node;
} else {
new_node->next = node->next;
node->next = new_node;
}
}
and finally:
void Link::insert(int number) {
insert_after(upper_bound(number), number);
}

Deleting a specific value from singly linked list?

I've been trying to delete a node if the data matches a specific value.
Here's my delete value method:
void del_value(int data)
{
Node *temp = head;
int i = 0;
while(temp!=NULL)
{
if(temp->data == data)
{
del_index(i);
i--; // Since the nodes count will be reduced after deleting, reducing the index by one.
}
i++;
temp = temp->next;
}
}
And here is my del_index method(Which is working correctly):
int getCount()
{
int i = -1;
Node *temp = head;
while(temp!=NULL)
{
temp = temp->next;
i++;
}
return i;
}
void del_index(int pos)
{
int count = getCount();
if(pos == 0)
{
del_start();
}
else if(pos == count)
{
del_last();
}
else if(pos<0 || pos>count)
{
cout<<"Out of range"<<endl;
return;
}
else
{
int i = 1;
Node *temp = head;
while(i<pos)
{
temp = temp->next;
i++;
}
Node *toDel = temp->next;
Node *forward = toDel->next;
temp->next = forward;
delete toDel;
}
}
And here is my main method:
int main()
{
Mylist l;
l.add_start(4);
l.add_start(4);
l.add_start(4);
l.del_value(4);
l.show();
}
But it stucks when it reaches del_value method inside loop. Any idea where am I missing?
Update: (Added del_first and del_last methods
void del_start()
{
if(head == NULL)
{
cout<<"List is empty"<<endl;
return;
}
else
{
Node *temp = head;
head = head->next;
delete temp;
}
}
void del_last()
{
if(head == NULL)
{
cout<<"List is empty"<<endl;
return;
}
else
{
Node *temp = head;
while(temp->next != NULL)
{
tail = temp;
temp = temp->next;
}
tail->next = NULL;
delete temp;
}
}
Your del_value method will not work because you delete the object being pointed to by 'temp' then you dereference it after (with "temp = temp->next").
For your example code, I would cache the 'next' value before your conditional, for example:
Node *next = temp->next;
if(temp->data == data)
{
del_index(i);
i--;
}
i++;
temp = next;
I am assuming you're doing this for practice purposes but I would add the following suggestions:
I wouldn't call del_index here but remove the node inline, within the del_value method. As you have the necessary pointers to be able to remove it. del_index has to traverse your list a second time.
I would also recommend using the containers within the stl instead of rolling your own to avoid encountering issues like this.

C++ linked lists deleting nodes

I am trying to go through a singly linked list and delete all nodes that contain a certain char. I have been trying to fix a pointer error (it said glibc detected: double free or corruption) by looking up online and trying those suggestions but now I seem to be stuck in a loop after rewriting my original code. I think the I am at least stuck in the 3rd while loop, I have tried using and if/else statement but the same thing happens. I also get a segmentation fault sometimes.
Code:
int MonsterList::removeMonsterType(char monster){
if(!isalpha(monster)) return 0;
if(first == 0) return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev = first; //first is the ptr in the list this function is called on
if(prev->next == 0){
while(prev->id == key || prev->id == key+32){
first = 0;
delete prev; prev = 0;
count++;
return count;
}
return count;
}
MonsterNode *temp = prev->next;
while(temp != NULL){
while(prev->id == key || prev->id == key+32){
first = temp;
delete prev;
prev = temp;
temp = temp->next;
}
while(temp->id == key || temp->id == key+32){
prev->next = temp->next;
delete temp;
temp = prev->next;
count++;
}
prev = temp;
temp = temp->next;
}
return count;
}
Thanks in advance for your help.
No wonder you're having such trouble. You only need a single for loop. Allow me to simplify your code [please pardon some gratuitous style edits]. Note this is untested and may not be perfect:
int
MonsterList::removeMonsterType(char monster)
{
if (!isalpha(monster))
return 0;
// first is the ptr in the list this function is called on
if (first == 0)
return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev;
MonsterNode *cur;
MonsterNode *next;
prev = NULL;
for (cur = first; cur != NULL; cur = next) {
// grab this _first_ so we have it before cur may be deleted (e.g. if
// cur gets deleted cur->next is immediately invalid, but this will
// remain)
next = cur->next;
if ((cur->id == key) || (cur->id == (key + 32))) {
// link previous item to next item
if (prev != NULL)
prev->next = next;
// replace first item in list
else
first = next;
// delete the node and advance the count
delete cur
count++;
continue;
}
// remember previous item
prev = cur;
}
return count;
}

Linked list not working for input

I'm writing code that takes integers that are input from the user and creates a linked list and then prints out the list. However, when I enter values 1,2,3,4,5, the output is only 5 5 5 5 5
Please tell me where am i wrong here.
The code is as follows:
include"iostream"
using namespace std;
struct node
{
int number;
node* next;
};
int main()
{
node* head;
head = NULL;
int i,n,x;
cin>>n;
cout<<endl;
for(i=0;i<n;i++)
{
cin>>x;
//Insert(x);
node* temp;
temp = new node;
temp->number = x;
temp->next = NULL;
head = temp;
}
//Print();
node* temp;
temp = head;
while(temp != NULL)
{
for(int j=0; j<n; j++)
cout<<temp->number<<" ";
temp = temp->next;
}
}
Remember that when setting the head pointer, you should only do so when the list is empty (i.e when head == NULL). We should do this after we create the new node so we know what to set head to:
node* temp = new node;
temp->number = x;
temp->next = NULL;
if (head == NULL) // if the list is empty then...
head = temp; // temp is the start of the list
There's also another problem. temp is supposed to be added to the end of the list each time it's created. If the list is empty then head is the end of the list, but if the list already has elements then we need to go to the end and set the next pointer of that node to temp. This is fairly straightforward, all it takes is a while loop to iterate over the list to the end:
if (head == NULL)
head = temp;
else // the list is not empty
{
// so we need to go to the end
node* p = head;
while (p->next != NULL)
p = p->next; // keep going through
// p now points to the last node
p->next = temp;
}
There's also the option of keeping a prev node that points to the last element inserted. This makes it so that we don't have to go through the list each time to find the end:
node* head = NULL, prev = NULL;
for (/* ... */)
{
// ...
if (head == NULL)
head = prev = temp;
else
{
prev->next = temp;
prev = temp;
}
}
The last thing is the way you're printing. You shouldn't have a nested for loop here:
while (temp != NULL)
{
for(int j = 0; j < n; j++)
cout << temp->number << " ";
temp = temp->next;
}
Taking it out will make it print correctly.
This looks a bit wrong:
while(temp != NULL)
{
for(int j=0; j<n; j++)
cout<<temp->number<<" "; // Only this is part of the for() loop
temp = temp->next; // This happens after the for() loop ends
}
Only the first line gets executed by the for() loop so it keeps outputting the same number. Why is the for loop there anyway? What is it supposed to do?
Try this:
while(temp != NULL)
{
cout<<temp->number<<" ";
temp = temp->next;
}
See if that works better.
ALSO:
As #crashmstr pointed out your insert logic is wrong:
for(i=0;i<n;i++)
{
cin>>x;
//Insert(x);
node* temp;
temp = new node;
temp->number = x;
temp->next = NULL; // this should point to the nextnode
head = temp;
}
Try:
for(i=0;i<n;i++)
{
cin>>x;
//Insert(x);
node* temp;
temp = new node;
temp->number = x;
temp->next = head; // the current begining
head = temp;
}
*ALSO 2:
include"iostream" // not right
Please use:
#include <iostream> // correct!