Reputation: 231
I am working on a function that would delete a node of a doubly-linked list. Here is my header file:
class LinkedList
{
private:
struct Node
{
int data;
Node *next;
Node *previous;
};
int count;
Node *head;
Node *tail;
public:
LinkedList() {head = NULL; tail = NULL; count = 0;} //Constructor
void insert(const int );
bool remove(const int );
bool contains(const int );
size_t lenght() {return count;}
};
My other functions work fine, but its my remove function that breaks on run-time. When i run my code i get a segmentation fault, and after 2 days of trying to figure out the flaw in my logic I am turning to the community for some help. I would be grateful for any feed-back at this point, thank you. Here is my remove function:
bool LinkedList::remove(const int item)
{//if the list is empty returns false
if(head == NULL) {return false;}
Node *hptr = head;
Node *tptr = tail;
if((hptr -> data) == item)
{//if the node is at the head of the list
hptr = hptr -> next;
delete head;
hptr -> previous = NULL;
head = hptr;
--count;
return true;
} else if((tptr -> data) == item) {
//if the node is at the tail of the list
tptr = tptr -> previous;
delete tail;
tail = tptr;
tptr -> next = NULL;
--count;
return true;
} else {//if the node is in he middle of the list
Node *ptr_head = head; Node *ptr_headp = NULL;
Node *ptr_tail = tail; Node *ptr_tailp = NULL;
while((ptr_head -> data) != item || (ptr_tail -> data) != item)
{//pointers pass each other then data was not found
if((ptr_tail -> data) < (ptr_head -> data)) {return false;}
//traversing the list from the head and tail simultaniously
ptr_headp = ptr_head;
ptr_head = ptr_head -> next;
ptr_tailp = ptr_tail;
ptr_tail = ptr_tail -> previous;
}
if((ptr_head == ptr_tail) && ((ptr_tail -> data) == (ptr_head -> data)))
{//the item is at the intersection of both head and tail pointers
ptr_headp -> next = ptr_tailp;
ptr_tailp -> previous = ptr_headp;
delete ptr_head;
delete ptr_tail;
--count;
return true;
}
if((ptr_head -> data) == item)
{//the item is before middle node
ptr_headp -> next = ptr_head -> next;
(ptr_head -> next) -> previous = ptr_headp;
delete ptr_head;
--count;
return true;
}
if((ptr_tail -> data) == item)
{//the item is after the middle node
ptr_tailp -> previous = ptr_tail -> previous;
(ptr_tail -> previous) -> next = ptr_tailp;
delete ptr_tail;
--count;
return true;
}
}
return false;
}
Upvotes: 1
Views: 19294
Reputation: 727137
This is a common example of a situation when changing the data structure a little could make the logic a lot simple by unifying the cases that otherwise look different *.
The main issue with the logic is that you have lots of conditions to check:
You can make these four conditions identical to the last one by ensuring that there is always a node on the left and a node on the right of any node. Here is how you can do it:
class LinkedList
{
private:
struct Node
{
int data;
Node *next;
Node *previous;
};
int count;
// The change begins here
Node headTail;
// End of the change
public:
LinkedList() {head = NULL; tail = NULL; count = 0;} //Constructor
void insert(const int );
bool remove(const int );
bool contains(const int );
size_t lenght() {return count;}
};
The head
pointer is headTail
's next
; the tail
pointer is its previous
. Both next and previous point back to itself in an empty list.
This is a little inefficient, because the data
of the headTail
is unused. The list becomes circular, with one node always present. With this node in place, you can safely remove any node in the middle, and update the prior and the next pointers as if they belonged to different objects.
Upvotes: 2
Reputation: 44201
// Locate the item to remove
Node* to_remove = head;
while(to_remove && to_remove->data != item)
to_remove = to_remove->next;
// Do the removal if we found it
if(to_remove)
{
// If it was at the head, advance the head to the next item
if(to_remove == head)
head = head->next;
// If it was at the tail, advance the tail to the previous item
if(to_remove == tail)
tail = tail->previous;
// Remove from the list
if(to_remove->next)
to_remove->next->previous = to_remove->previous;
if(to_remove->previous)
to_remove->previous->next = to_remove->next;
// Free the removed node
delete to_remove;
count--;
return true;
}
return false;
Upvotes: 1