Remove Ith element - c++

void removeIelement(Dlist& d, int i) {
if (d.head == NULL) {
cout << "EMPTY" << endl;
return;
}
else {
int count = 1;
Node* cur = d.head;
while (cur != NULL) {
if (count == i) {
Node* temp = cur->next;
Node* temp2 = temp->next;
cur->next = temp->next;
temp2->prev = cur;
}
count++;
cur = cur->next;
}
}
}
Here is my code to delete Node ith in doubly linked list
My doubly linked list is :
1 2 3 4 5 6 7 8 9 10
But when I run this program if I enter i = 1 it will delete
1 3 4 5 6 7 8 9 10
Same with i = 2 .... it will delete after element i (i+1)
1 2 4 5 6 7 8 9 10
Can you help me to fix this function? Thank you

You are not deleting anything. You are linking around temp, but since it's never actually deleted, you just leak the memory instead. You match against cur, meaning you want to delete cur, but then you assign temp to cur->next. You are linking around cur + 1, which is why you always unlink (not delete) the (i + 1)st node. You don't need any temps, either; the list is doubly linked. Take advantage of that. Erasing is incredibly easy in doubly-linked lists. After the delete command, your function should immediately return as well. Its job is done.
This code does not account for deleting the tail node, since I don't know if you track that or not. If you do, you need to account for that scenario as well.
void removeIelement(Dlist& d, int i) {
if (d.head == NULL) {
cout << "EMPTY" << endl;
return;
}
else {
int count = 1;
Node* cur = d.head;
while (cur != NULL) {
if (count == i) {
cur->next->prev = cur->prev; // Added
cur->prev->next = cur->next; // Changed
if (cur == head) { // Added
head = cur->next; // Added
} // Added
delete cur; // Added
return; // Added
}
count++;
cur = cur->next;
}
}
}
This could have been resolved by just drawing it on a piece of paper. Doing that beforehand would have eliminated this issue altogether. Planning is one of the most important aspects of programming.

A double linked list should have 2 attributes named begin and end, pointing to two "empty" places, head->next should point to the 1st element, and end->pre should point to the last element, your code assumes head as the first element, when it tries to remove the first element, it removes the element right after head, which is the element after the first element. A.K.A the second element.
the correct code may look like this:
void removeElement(Dlist& d, int id){
if(d.head->next==d.tail){
// the list is empty
cout << "empty list" <<endl;
}
else{
int count = 1; Node* cur = d.head->next;
while(cur->next != NULL)
if(count == id){
cur->prev->next=cur->next, cur->next->prev=cur->prev;
delete cur;
return; //removal successful
}
else
count++, cur = cur->next;
cout << "does not exist." << endl;
}
}
note that I didn't test the code. There might be some issues, but you got the idea.

Related

Delete Nodes With The Value 0 In Singly Linked List In C++

I can't for the life of me figure this out I've spent days on this exercise but to no avail.
I'm trying to delete nodes with the value 0 from a singly liked list.
Let's say i have |1|3|0|4|0|5|0|0|. The outcome should be |1|3|4|5|
Here is all the code for reference
#include <iostream>
#include <fstream>
using namespace std;
struct node {
int data;
node* next;
};
node* head, *last;
int n;
void creating_list()
{
node* aux;
ifstream f("in.txt");
f >> n;
for(int i=0;i<n;i++)
{
if (head == NULL)
{
head = new node;
f >> head->data;
head->next = NULL;
last = head;
}
else
{
aux = new node;
f >> aux->data;
last->next = aux;
aux->next = NULL;
last = aux;
}
}
}
void displaying_list()
{
node* a;
a = head;
if (a == NULL)
cout << "List is empty! ";
else
{
cout << "Elements of list are: | ";
while (a)
{
cout << a->data<<" | ";
a = a->next;
}
}
}
void delete_first_node()
{
if (head == NULL)
cout << "List is empty";
else
{
cout << "Deleting first node\n";
node* aux;
aux = head;
head = head->next;
delete aux;
}
}
void delete_last_node()
{
if (head == NULL)
cout << "List is empty";
else
{
if (head == last)
{
delete head;
head = last = NULL;
}
else
{
node* current;
current = head;
while (current->next != last)
current = current->next;
delete current->next;
current->next = NULL;
last = current;
}
}
}
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
int main()
{
creating_list();
displaying_list(); cout <<endl;
delete_value_0();
return 0;
}
Here is the problem that gives me metal problems
I've tried to move one node short of the node that has the 0 value, store the value in another node, aux in this case and delete aux;
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
If I put break at the end it only shows me the first few numbers until the 0 and then stops short, doesn't move through the full list.
if I don't put break the the program is doesn't stop, it's in an infinite loop, it doesn't exit with code 0
void delete_value_0()
{
node* aux;
if (head == NULL)
cout << "List is empty. Can't delete! ";
else
// if (head->data == 0)
// delete_first_node();
// if (last->data == 0)
// delete_last_node();
// else
{
node* a;
a = head;
while (a)
if (a->next->data != 0)
{
a = a->next;
cout << a->data<<" | ";
}
else
if (a->next != last)
{
aux = a->next;
a->next = a->next->next;
delete aux;
break;
}
}
}
Honestly I'm at a loss I've spent so much time trying to figure this out, and this should be a very simple exercise. I feel like the answear Is really simple but i don't know what to do anymore, Maybe this is not for me.
This is much simpler than it appears on the first glance. The trick to this task is instead of using a pointer to the current node, a pointer to the pointer to the current node gets used instead. The entire task becomes laughably trivial: only one loop, and one if statement that takes care of all possibilities: the list is empty; the node to delete is the first node in the list; ot the last node in the list; or anywhere in the middle of it.
void delete_value_0()
{
node **p= &head;
while (*p)
{
if ((*p)->data == 0)
{
node *nextptr=*p;
*p=(*p)->next;
delete nextptr;
}
else
{
p= &(*p)->next;
}
}
}
The naive solution is something like this:
void delete_value_0()
{
while (head && head->data == 0)
delete_first_node();
if (head == nullptr)
return;
node *cur = head->next;
node *pre = head;
while (cur)
{
if (cur->data == 0)
{
pre->next = cur->next;
delete cur;
cur = pre->next;
}
else
{
pre = cur;
cur = cur->next;
}
}
}
The key point is that you need to have a pointer to both the element you are inspecting and to the previous element in the list. This allows you to pull the current element out if it has data == 0.
The issue with this is that you have to treat the first element special (since it has no previous element).
My suggestion is to study this solution until you understand how it works, then move on to the (much better) solution by #Sam Varshavchik and study that - it does basically the same, but uses a pointer to pointer in a clever way to make the special cases here irrelevant.
I've put comment on those lines because if I don't and the condition it's met it doesn't execute the rest of the code...
OK why there the sketchy iteration is in else for if (last->data == 0)? Your input seems to have 0 as last item so in this case it would never be triggered. Also, if you want to have first/last items as special case, instead of
if (head->data == 0)
delete_first_node();
you would want something like
while (head && head->data == 0)
delete_first_node();
That being said, the real WTF is treating first/last item specially instead of using just single iteration. Also, you don't really check whether the pointers are non-null before trying to access the contents. With C (or C++ in the case you try it at some point) you need to take care with memory access when dealing with pointers.
Some random pieces of help:
You need to break from last item when it's 0 to exit loop simply because you don't assign a to the next item in this case.
If this is your schoolwork this might not be your fault, reading amount of items from the input file (assuming it was given part of the assignment) before actual items is huge WTF as you're reading into a linked list. There is no need to loop for any n items when you can be simply reading a line of input at the time until the file runs out.
Arguments and return values. You should learn those.
#include <iostream>
struct Node {
int data;
Node* next;
};
// Function to delete nodes with the value 0 in a singly linked list
void deleteNodes(Node** head) {
// Edge case: empty list
if (*head == nullptr) {
return;
}
// Delete all nodes with the value 0 at the beginning of the list
while (*head != nullptr && (*head)->data == 0) {
Node* temp = *head;
*head = (*head)->next;
delete temp;
}
// Edge case: list with only one node
if (*head == nullptr) {
return;
}
// Delete nodes with the value 0 in the rest of the list
Node* current = *head;
while (current->next != nullptr) {
if (current->next->data == 0) {
Node* temp = current->next;
current->next = temp->next;
delete temp;
} else {
current = current->next;
}
}
}
int main() {
// Create a singly linked list: 1 -> 0 -> 2 -> 0 -> 3 -> 0 -> 4
Node* head = new Node{1, new Node{0, new Node{2, new Node{0, new Node{3, new Node{0, new Node{4, nullptr}}}}}};
// Delete nodes with the value 0
deleteNodes(&head);
// Print the resulting list: 1 -> 2 -> 3 -> 4
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
return 0;
}
hope it help

Cannot Insert Item into Linked List

void LinkedList::insert(int num, int pos) {
Node *newNode = new Node;
newNode->data = num;
newNode->next = NULL;
if(pos == 0) {
newNode->next = head;
head = newNode;
}
else {
Node *temp = head;
for (int i = 1; i < pos-1; ++i) {
if (temp != NULL) {
temp = temp->next;
}
}
if (temp != NULL) {
newNode->next = temp->next;
temp->next = newNode;
}
else {
cout << " The previous node is full.";
}
}
}
This is my insert function.
The code that runs in main.cpp is:
// adding through insert
nums.insert(1, 0);
nums.insert(5, 4);
nums.insert(3, 7);
And the output is:
List after append:
8 6 7 8 0 9
List after inserting:
1 8 6 5 7 8
As you can see, something is getting overwritten, or the end of the list just gets cut off. I have searched the internet for hours to no avail. The output needs to increase the length of the list and not overwrite anything. Any help would be appreciated.
The problem is this for loop
for (int i = 1; i < pos-1; ++i) {
if (temp != NULL) {
temp = temp->next;
}
}
Let's assume that pos is equal to 2. In this case the loop will not iterate and temp will be equal to head. So the new node will be inserted before the second mode instead to be inserted before the third node.
You need to write
for (int i = 1; temp != nullptr && i < pos; ++i) {
temp = temp->next;
}
Also instead of writing this message
cout << " The previous node is full.";
(it is the caller of the function should decide whether to output a message) I would declare the function like
bool LinkedList::insert(int num, int pos) {
and return either true or false dependent on whether a node was inserted.

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

Remove function malfunctioning in doubly linked list

My function to remove nodes from a doubly linked list is adding (overwriting?) values to the list, which appear when the list is printed.
Code for the main, remove and print functions is listed below. The expected output and correlations between the current code and its output are shown below too.
Code for main
In main, the add function is called, and the integer in the parameter is added as a node in the linked list. The add function works, as does the print function.
int main()
{
LinkedList aList;
aList.add(3);
aList.add(10);
aList.add(1);
aList.add(7);
aList.add(9);
aList.add(12);
aList.printAscending();
aList.printDescending();
aList.remove(3);
aList.remove(1); //The integer to be removed with this line ends up in the output
aList.remove(7);
aList.remove(12);
cout << "remove operations should be complete" <<endl;
aList.printAscending();
aList.printDescending();
return 0;
}
Code for remove function
bool LinkedList::remove(int val) //parameter contains value to be removed
{
bool removed = false;
Node* newNode = new Node;
newNode->data = val;
newNode->next = NULL;
newNode->prev = NULL;
Node* curr = head;
while(curr)
{
if(curr->data == val)
{
if(curr == head)
{
head = head->next;
curr->next = NULL;
delete curr;
}
else if(curr != head && curr != tail)
{
Node * previous = curr->prev;
Node * following = curr->next;
previous->next = following;
following->prev = previous;
curr->next = NULL;
curr->prev = NULL;
delete curr;
}
else if(curr == tail)
{
tail = tail->prev;
curr->prev = NULL;
delete curr;
}
removed = true;
}
curr = curr->next;
}
return removed;
}
Code for print functions
//Prints from head to tail of list
void LinkedList::printAscending() const
{
Node* curr = head;
cout<<"\nascending: ";
while(curr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout <<'\n';
}
//Prints from tail to head of list
void LinkedList::printDescending() const
{
Node* curr = tail;
cout << "\ndescending: ";
while(curr)
{
cout << curr->data << " ";
curr = curr->prev;
}
cout << endl;
}
Expected output
ascending: 3 10 1 7 9 12
descending: 12 9 7 1 10 3
remove operations should be complete
ascending: 10 9
descending: 9 10
Actual Output
ascending: 3 10 1 7 9 12 //correct
descending: 12 9 7 1 10 3 //correct
remove operations should be complete //correct
ascending: 10 9 0 //last number, 0, is incorrect
descending: 9 10 1 //last number, 1, is incorrect
If the call in int main to remove the integer 1 aList.remove(1) is replaced with aList.remove(999), the integer 999 appears in the actual output on the descending print instead of 1. However, the integer 0 is appended to the ascending print at all times.
As well as the undefined behavior that Beta pointed out, you have a problem with both your special cases for head and tail. Running this through a debugger and inspecting the values in your list after each deleted would have shown you what is going wrong.
This code:
else if(curr == tail)
{
tail = tail->prev;
curr->prev = NULL;
delete curr;
}
does not do anything with the next pointer of the second last element. This means your second last element (which then becomes the last element) has a next pointer that points to freed memory.
To fix it, you need to set the second last element's next pointer to null. Something like this:
else if(curr == tail)
{
tail = tail->prev;
tail->next = NULL;
curr->prev = NULL;
delete curr;
}
But wait! There is (almost*) no guarantee that the previous element existed (i.e. in a 1 element list), so you need to check that the new tail is not NULL.
else if(curr == tail)
{
tail = tail->prev;
if (tail != NULL)
tail->next = NULL;
curr->prev = NULL;
delete curr;
}
*Actually if this was a single element list, you would not reach this code, you would have already gone through the "head" if test code, which has a similar problem in that it doesn't change the second node's prev pointer.
So you need to also do the same sort of test in the "head" if test code.
Once you have done that, you might find that you can rearrange the tests to get rid of repeated code.
After you delete curr, you then dereference it:
curr = curr->next;
This is undefined behavior.

While loop with pointers does not work

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