You're actually using a slight variation on the normal deletion logic, which works in most cases. That variation is, rather than deleting the current element, you move the data from the following element into it, then delete that following element. This means you never have to back up to the previous element, something that's difficult (without storing extra info or running through the list again) with a singly-linked list.
Unfortunately, the one case where that won't work is when you're deleting the final element in the list. In that case, there is no following element to move the data from and you therefore need to delete the current element and adjust the previous element to become the new end of the list.
And, since you need to do that anyway, you may as well revert to the normal logic for all cases :-)
With that logic, you basically need to have access to the element before the one you want to delete. Then you set its next
pointer to bypass the one you're deleting.
You'll need to also handle the special case of deleting the first element in the list. Assuming you have a head
member pointing to the first element and curr/prev
pointing respectively to the node you want to delete and its predecessor, the pseudo-code would be:
if curr is head:
set head to curr.next
else
set prev.next = curr.next
free curr
One way to do this easily without involving too many changes is to modify your find
method so that you can also use it to get the previous node as well:
Node* Collection::find(
int num,
Node **pPrev = nullptr
) {
// Initially store null as previous item.
if (pPrev != nullptr) *pPrev = nullptr;
// Cycle through list until found or not there.
Node *temp = head;
while ((temp != nullptr) && (temp->num != num)) {
// Update previous before advancing.
if (pPrev != nullptr) *pPrev = temp;
temp = temp->next;
}
return temp;
}
Note that I've just used Node
in the code rather than Collection::Node
, since your question had both variants and I'm unsure whether you're in a namespace called Collection
. Simply adjust as necessary, based on your actual usage.
In any case, defaulting the second parameter to nullptr
will allow you to call it exactly as you do currently (with one parameter, it won't bother trying to store the previous node pointer).
But, in the case where you want that previous pointer, you would use something like this to delete:
Node *prev;
Node *curr = find(num, &prev); // Get previous as well.
if (curr != nullptr) { // Only delete if actually found.
if (prev == nullptr) // Null means current is head.
head = curr->next;
else // Otherwise adjust previous.
prev->next = curr->next;
delete curr; // Regardless of head-ness, delete.
}