Home > Mobile >  Delete Nodes With The Value 0 In Singly Linked List In C
Delete Nodes With The Value 0 In Singly Linked List In C

Time:01-03

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.

CodePudding user response:

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

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

    #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

  • Related