0

To start: this is part of a homework problem so feel free to just hint at the answer or point me in the right direction instead of directly answering.

I am creating a single linked list in c++ one of the required functions is void remove(const T& key) where a given node is removed if the value matches that of the key passed into the function.

My current thinking is to do that I must first, find the node to be deleted, find the node before the one to be deleted, and find the node after the one to be deleted. From there I can delete the node that needs deleted and set the previous node to point toward the node that came after the deleted node.

Here are the relevant functions:

LinkedList.h

//Returns the node with passed in value key
ListNode<T>* find(const T& key) {
    ListNode<T>* currentNode = _head;
    while(currentNode != NULL && currentNode->data() != key){
        currentNode = currentNode->next();  
    }
    return currentNode; 
}

//Returns the node before the key
ListNode<T>* findPreviousNode(const T& key){
    ListNode<T>* previousNode;
    ListNode<T>* currentNode = _head;

    while(currentNode != NULL && currentNode->data() != key){
        previousNode = currentNode;
        currentNode = currentNode->next();  
    }
    return previousNode;
}

// Removes and deletes the first node in the linked list that has data
// equal to the  key
void remove(const T& key) {
    ListNode<T>* nodeToDelete = find(key);
    ListNode<T>* previousNode = findPreviousNode(key);
    ListNode<T>* nextNode = nodeToDelete->next();
    delete nodeToDelete;
    previousNode->setNext(nextNode);

}

I have tested my find(const T& key) function extensively and it works so I believe the issue is in my findPreviousNode function, however when I walk through the code it seems to work fine.

It seems to me that previousNode will always have the last checked element and when a match is found it returns previousNode which hasn't been updated yet so it still contains the node directly before the matching node, however this clearly isn't correct and I am not sure why. When I run the code I get a

segmentation fault (core dumped)

error message

Here are some pastebins with the entire code:

LinkedList.h http://pastebin.com/b4miZBzA

main.cpp(the method that calls the test functions) http://pastebin.com/0QGtUhjC

kalenpw
  • 695
  • 3
  • 10
  • 34
  • May be helpful: http://stackoverflow.com/questions/12914917/using-pointers-to-remove-item-from-singly-linked-list – user4581301 Feb 24 '17 at 05:35

2 Answers2

2

From the code you've posted here in the question, it looks like you have the right idea.

Two tips:

  1. Defensive programming. Check that nodeToDelete and previousNode are not NULL. Currently, if the key is not found, you will end up dereferencing a NULL pointer, which could be the cause of your segmentation fault.

  2. Efficiency. Why traverse the list twice (once in 'find', and once in 'findPrevious'), when you could just traverse it once and get both values? I.e. combine the find() and findPrevious() functions to reduce the amount of work the program has to do.

nibot
  • 14,428
  • 8
  • 54
  • 58
  • for 1 I believe that is the issue which I'm working on. for 2 while coding that I definitely felt it was inefficient, but because sometimes I need the node and other times the previous node I split it into two functions because I can't change the method parameters to include a boolean or something to indicate if I want to return previous or current – kalenpw Feb 24 '17 at 05:19
2

You're clearly missing a lot of Edge Cases in there.

Your find() function is not handling the case where key is not found. In that case it's returning null, for which the findPreviousNode() returns garbage value for previousNode.

Assuming find() returns pointer to head. Then again your findPreviousNode() returns uninitialized previous Node pointer.

Try to handle the Edge cases in your code.

Your remove() function should work fine assuming those are handled.

Also you don't really require to call find() function, then you can really improve the runtime by just returning appropriate values from findPreviousNode(), as you're running two loops which is unnecessary and thus you can save on your runtime.

Abhinav S
  • 111
  • 3
  • 12
  • The instructions for `find()` were to return NULL if the value is not found, but now I do see how that could cause problems in findPreviousNode() when it tries to get the next node of a null value. I'll try and mess with that and see if that fixes anything. – kalenpw Feb 24 '17 at 05:17
  • Read the last line in my answer and try to work using that for your Code Inefficiency Problem. – Abhinav S Feb 24 '17 at 05:24
  • Why don't I need to run the find() function? That is required so I can delete the corresponding node – kalenpw Feb 24 '17 at 05:27
  • Just a hint: You're doing the same thing in findPreviousNode() function. If you can just get the previous node from findPreviousNode() function then you don't really require find() as the output of find() can easily be obtained from output of `findPreviousNode()->next();` Give it your best shot, then let me know if you need more help. – Abhinav S Feb 24 '17 at 05:30
  • ooh duh that makes sense. Thanks. – kalenpw Feb 24 '17 at 05:30
  • Of course, but I am going to wait a bit longer until I figure it out and see if anyone else answers – kalenpw Feb 24 '17 at 05:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/136517/discussion-between-phoenix-and-kalenpw). – Abhinav S Feb 24 '17 at 05:56
  • 1
    The issue ended up being one of the tests removes the first element of the LinkedList and I was trying to set the null pointer that preceded that. Thanks for the answer – kalenpw Feb 24 '17 at 22:40