Deleting elements from doubly bounded pointer list - c++

I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else

To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library

One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.

Related

Why is the delete temp crashing even though the function is defined with new

I am making a modified double ended Linked List, but the head and the tail point to each other. In the insertBeforeCurrent and the insertAfterCurrent I defined the objects with new and put them into the Linked List. But when I go to use delete, the program just crashes. I have done some tests, and insertBeforeCurrent and insertAfterCurrent works, and I am able to through the Linked List and print every single element with the getPrevious and getNext. I also printed it using only insertBeforeCurrent, insertAfterCurrent and I was also able to do the same with the mixture of the two. I was able to print it with 1,2,3,and 6 elements in the Linked List. The problem I have is the debugger, everything works until I hit the delete temp; at which point it will just say.
Can't find a source file at "/build/glibc-t7JzpG/glibc-2.30/signal/../sysdeps/unix/sysv/linux/raise.c"
Locate the file or edit the source lookup path to include its location.
I know you can only use the delete function for delete the data created by the new's dynamic memory allocation, but that doesn't seem to be the case since every element of the Linked List is created by new.
So the issue with application crashing is not the Node * x = new Node(); followed by x = y;. These don't show any warnings,the application runs, and 5 or 6 people have pointed them out. Thank you by the way. My issue is specifically is the delete temp;and why is it not being deleted. I have left the code for some context.
EDIT: I have removed the insertBeforeCurrent and insertAfterCurrent code since it is not needed.
bool CircularDoublyLinkedList::remove(int original_data)
{
Node search_data = search(original_data);
Node* temp = &search_data;
Node* current_next;
Node* current_previous;
if (temp != NULL)
{
if (temp == head)
{
current_previous = temp->getPrevious();
current_next = temp->getNext();
current_previous->setNext(current_next);
current_next->setPrevious(current_previous);
head = current_next;
temp->setNext(NULL);
temp->setPrevious(NULL);
delete temp;
current = current_next;
cout << "Delete successful." << endl;
}
else if (temp == tail)
{
current_previous = temp->getPrevious();
current_next = temp->getNext();
current_next->setPrevious(current_previous);
current_previous->setNext(current_next);
tail = current_next;
temp->setNext(NULL);
temp->setPrevious(NULL);
delete temp;
current = current_next;
cout << "Delete successful." << endl;
}
else
{
current_previous = temp->getPrevious();
current_next = temp->getNext();
current_previous->setNext(current_next);
current_next->setPrevious(current_previous);
temp->setNext(NULL);
temp->setPrevious(NULL);
delete temp;
}
return true;
}
return false;
}
I know you can only use the delete function for delete the data created by the new's dynamic memory allocation,
So far so good.
but that doesn't seem to be the case since every element of the Linked List is created by new.
This is not relevant, since the temp in CircularDoublyLinkedList::remove() never points to an element of the linked list. You assign to temp the address of a local variable (search_data) and never change that. Local variables are not created by new, so (as you noted earlier), you cannot delete &search_data.
(You might have noticed this yourself had you used a debugger to step through your code while trying to delete the first element of the list. In your current code, temp == head will never be true, even though that is the branch for deleting the first element. Similarly, temp == tail will never be true, and temp != NULL will never be false.)
At a guess, your search() function should probably return a pointer to a node in the list instead of returning the node, at which point you'll no longer need the (poorly-named) temp variable.

c++ link list remove all method is leaving last element unremoved

I have developed a function to remove all nodes from linked list. All nodes are successfully deleted except the last one. Please help me why last node is not being deleted? Following is my code:
void StudentLinkList::removeAll() {
StudentData *traversePointer = this->head;
while (this->head->getNext() != nullptr) {
this->head = this->head->getNext();
delete traversePointer;
traversePointer = this->head;
}
delete this->head;
}
So close
void StudentLinkList::removeAll() {
StudentData *traversePointer;
// Continue while there are any elements on the list
// Extra parens to indicate that we want the result of the
// assignment as boolean. No need to compare to nullptr.
while ( (traversePointer = this->head) ) {
// First preserve the rest of the list
this->head = this->head->getNext();
// only then can we delete this node
delete traversePointer;
}
// list is now empty
}
You're deleting this->head, but you should set this->head to nullptr as well. While you're freeing the memory the node is using, the data stored in the node's old location usually isn't immediately overwritten, which is why it looks like the last node is not deleted.
EDIT: downvote is duly noted, could someone clarify what I got wrong?
Also, I agree with the above comment - you should also check if this->head is null before the loop.

Circular Singly Linked List: Remove a particular Node from List

I wrote the code to remove a particular node from list according to user
choice, code works perfectly fine for a particular value but if i make
several calls to it meaning if I call it 2 times continuously then one of my
another function pointer_to_node(index) gives an out of bounds error which
was also implemented by me to record such conditions,
Actually, why I need several calls is that I have to write a separate function
to remove all the nodes. I am trying to accomplish that task using this
function by using a for loop up to the size of my Circular Singly Linked list.
But in that case it also returns me a NULL pointer and gives me out of bounds
message (implemented by me in code). I have included both my functions down
here
void remove_from_index(int index){
Node*temptr;
temptr = new Node;
int tempdata;
if (index==1)//means remove from first
{
temptr = firstptr;
tempdata= temptr->data;
firstptr = firstptr->nextptr;
lastptr->nextptr=firstptr;
delete(temptr);
} else if(index==size_of_list()) //means last node
{
temptr = pointer_to_node(index);
index--; //get pointer of 2nd last position
lastptr = pointer_to_node(index);//setting 2nd last as last postion
temptr->nextptr=NULL;
temptr=NULL;
lastptr->nextptr=firstptr;
delete (temptr);
} else // any position of node
{
temptr = pointer_to_node(index);
tempdata = temptr->data;
index--; // to get address of back
Node* temp2ptr;
temp2ptr = new Node;
temp2ptr = pointer_to_node(index);
index = index+2;
Node* temp3ptr;
temp3ptr = new Node;
temp3ptr = pointer_to_node(index);
temp2ptr->nextptr = temp3ptr;
temptr->nextptr=NULL;
delete (temptr);
}
}
Node* pointer_to_node(int index){
Node*temptr;
temptr = new Node;
temptr = firstptr;
Node*temptr2;
temptr2 = new Node;
temptr2 = NULL;
int count = 1;
while (temptr!=temptr2){
if (count==index)
{
return temptr;
}
count++;
temptr2=firstptr;
temptr=temptr->nextptr;
}
if (index>size_of_list())
{
temptr=NULL;
cout<< "Can't You think in bounds. Take your NULL Pointer ";
return temptr;
delete temptr;
delete temptr2;
}
}
You have several memory leaks:
temptr->nextptr=NULL;
temptr=NULL; // BAD!! BAD!! Remove it otherwise you will not actually free
lastptr->nextptr=firstptr;
delete (temptr);
And here too (actually you have this in four places of the code):
Node* temp2ptr;
temp2ptr = new Node; // BADD!! Why do you allocate if you are going to reassign?
temp2ptr = pointer_to_node(index);
Remove the bads and you will avoid the memory leaks.
Still, this is not going to fix your problem.
Also you have operations after return here:
return temptr;
delete temptr;
delete temptr2;
These are never going to be executed.
EDIT Your pointer_to_node function is too complex please change it with
Node* pointer_to_node(int index) {
Node* tempPtr = firstptr;
for (int i = 0; i < index; i++) {
tempPtr = tempPtr->nextptr;
}
return tempPtr;
}
And see if this will fix your problem. More lines of code very rarely means better programming skills, do not artificially try to increase their count.
I think another possible issue here, aside from all the memory leaks and style issues which are already well documented, is that your code does not seem to handle the case of there only being one thing in the list.
If that happens, it will delete that node, but leave firstptr and lastptr pointing at random memory.
If your size_of_list() function is just counting nodes in the list, it will probably still think there are non-zero nodes remaining, and you might then attempt to remove or otherwise access another node.

C++ - Single Linked List - Ideas

I want to write a method to remove consecutive items with duplicate data values from a singly linked list. The method should return the number of items removed. The method should clean up memory as required, and should assume that memory was allocated using new.
For example, passing in the list
->a->b->c->c->a->b->b->b->a->null
should result in
->a->b->c->a->b->a->null
and return 3
The list item definition and function declaration are given below
struct litem {
char data;
litem* next;
};
int remove_consecutive_duplicates( litem*& list );
I have a simple logic to check the next element recursively & removing the element if its duplicate.
But, i would like to know how many efficient ways to do this ? All ideas welcome from C++ gurus..
You can use std::list, and before pushing element on it you must check:
if ((*l.rbegin()) == next)
{
return;
}
l.push_back(next);
in meta language:
item = items.first
while (item != null) {
while (item.next != null && item.value = item.next.value) {
temp = item.next
item.next = item.next.next
temp.dispose
}
item = item.next
}
As far as I can see, there's not a lot to optimize here. Returning the number of items used is just a case of incrementing a counter. Basically, if you find that litem->data == litem->next->data, then you need to do the removal like so:
litem* tmpItem = currentItem->next;
currentItem->next = tmpItem->next;
delete tmpItem;
Keep iterating until currentItem->next == NULL, to avoid referencing beyond the end of the list.

Swapping Nodes on a single linked list

I am trying to make a swapNode function that can take any two nodes and swap them. I've made an algorithm that works if they're at least 2 nodes away, but I can't seem to come up with an algorithm that will work if they are closer to each other.
Here's what I wrote so far:
void swapNode(call * &head, call * &first, call * &second){
call * firstPrev = NULL;
call * secPrev = NULL;
call * current = head;
//set previous for first
while((current->next != first) ){
current = current->next;
}
firstPrev = current;
current = head;
//set previous for second
while((current->next != second) ){
current = current->next;
}
secPrev = current;
current = second->next;
//set firstPrev-> next to second
firstPrev->next = second;
//set secPrev->next to first
secPrev->next = first;
//set second->next = first->next
second->next = first->next;
//set first->next to current
first->next = current;
current = head;
while(current->next != NULL){
cout << current->number << endl;
current = current->next;
}
cout << current->number << endl;
}
EDIT:
I now have this as my swap part, but it still doesn't seem to work correctly
//swap firstPrev-> next with second->next
tmp = firstPrev->next;
second->next = firstPrev->next;
second->next = tmp;
//swap swap first->next with second->next
tmp = first->next;
second->next = first->next;
second->next = tmp;
EDIT2:
This one doesn't seem to work either, I get a seg fault.
//swap previous's->next
tmp =firstPrev->next;
secPrev->next = firstPrev->next;
secPrev->next = tmp;
//swap swap first->next with second->next
tmp = first->next;
second->next = first->next;
second->next = tmp;
Say we have:
Node1 -> Node2 -> Node3 -> Node4 -> Node5
To swap two nodes, you need to swap the next values of the ones before each of them, and also the next values of the nodes you want to swap.
So to swap, say, Node2 and Node3, you effectively have to swap Node1->next with Node2->next, and Node2->next with Node3->next. That will work, even if they're right next to each other (or even if it's the same node). For example:
Swap Node1->next and Node2->next
Node1->next = Node3
Node2->next = Node2
Swap Node2->next with Node3->next
Node2->next = Node4
Node3->next = Node2
This comes out as:
Node1 -> Node3 -> Node2 -> Node4 -> Node5
Swapped!
As unwind noted in the comments section, if swapping Node1 with anything, you'll have to set a new head for the linked list.
In response to the edit of the question:
Your code for swapping almost right. However, you need to swap the firstPrev with secPrev. It just so happened in my example that we were swapping one of the node's next values twice, because they were next to each other. But logically, we want to swap the nexts of the two previous ones, and then swap the nexts of the actual nodes. Try this:
//swap firstPrev-> next with secPrev->next
tmp = firstPrev->next;
secPrev->next = firstPrev->next;
secPrev->next = tmp;
//swap swap first->next with second->next
tmp = first->next;
second->next = first->next;
second->next = tmp;
If you're getting a segfault, check the tmp variable - it could be an error of allocation or deletion somewhere. Where do you get the segfault?
In most real-life scenarios, swapping the values will be the best solution:
void swapNode(call * &head, call * &first, call * &second) {
// swap values, assuming the payload is an int:
int tempValue = first->value;
first->value = second->value;
second->value = tempValue;
}
If that's not allowed, then you want to do a similar-style swap on the ->next instead of the ->value component. And then do another swap on the firstPrev->next and secondPrev->next components. Watch out for the special case where first or second == head.
You will have to also swap the next component of the previous node, otherwise the linked list will not remain joined together. Note that my struct is called node.
int swapNode( node *&head * &first, node * &second)
{
//first we will declare the
//previous of the swapping nodes
node *firstprev=NULL;
node*secprev=NULL;
node*current=head;
//set previous first
while(current->next!=first)
{
current=current->next;
}
firstprev=current;
//seting 2nd previous
while(current->next!=second)
{
current=current->next;
}
// swap values, assuming the payload is an int:
int tempValue = first->value;
first->value = second->value;
second->value = tempValue;
//swaping next of the nodes
firstprev->next=second;
secprev->next=first;
return;
}
Rule of thumb: "Always separate data from pointers and never swap pointers, only the data!". Make swap explicit without using memcpy(), thus you can avoid alignment problems. It causes no performance penalty in terms of algorithmic complexity, but makes your code more readable and safe.
Here p1 is the 1st node to be swaped, p2 is 2nd node to be swaped. And prevnode is the node that is previous of p2
temp=head;
while(temp!=NULL){
if(temp->link==p1){
temp->link=p2;
prevnode->link=p2->link;
p2->link=p1->link;
t=p1->link;
while(t!=prevnode)
t=t->link;
cout<<" YES";
cout<<"["<<t->num<<"] ";
p1->link=prevnode->link;
prevnode->link=p1;
temp=p1;
}//if_
cout<<" "<<temp->num;
temp=temp->link;
}
While I am not 100% sure the answer should involve references to node pointer (or pointers to pointers) and this should then handle a case when one of the nodes is the head of list as well.
void swapNodes(node *&first, node *&second)
{
node *t = second->next;
second->next = first->next;
first->next = t;
t = second;
second = first;
first = t;
}
Then you can call it for example:
swapNodes(head, secPrev->next);
or
swapNodes(firstPrev->next, head);
or
swapNodes(firstPrev->next, secPrev->next)
and it should work automagically.
EDIT:
swapNodes could be even more readable:
void swapNodes(node *&first, node *&second)
{
std::swap(first->next, second->next);
std::swap(first, second);
}
void swap()
{
struct node *temp=0,*nxt,*ptr;
ptr=head;
int count=0;
while(ptr)
{
nxt=ptr->link;
if(nxt)
{
if(count==0)
head=nxt;
count++;
ptr->link=nxt->link;
nxt->link=ptr;
if(temp!=NULL)
temp->link=nxt;
temp=ptr;
if(ptr->link==NULL)
break;
ptr=nxt->link->link;
}
}
}
Thank you everyone for your answers! I do realize that this question has been asked almost two years ago and an answer long been accepted, but I have been a bit confused by the answers. Thus, despite the questioner probably not caring about new answers, I would like to add my version, in case other readers were confused as well and to document my own approach. Some of this may have been more fitting as comments, but I do not have the reputation to comment, yet.
First, no matter how often I look at it - on the whiteboard or in the debugger - I cannot seem to avoid ending up with a loop in the first node, i.e. pointing to itself, if I do not use a conditional to distinguish between cases of nodes being adjacent and not, even with the abstract steps or the concrete code from the currently accepted answer by Smashery. I have looked around a bit on the Internet to find code in the style of the currently accepted answer to avoid such a conditional, but to me it is surprisingly tricky to avoid and my searches have not turned up such a solution (unless I am wrong about the proposed one possibly being incorrect). If there was some clever expression that would yield the first node's address when they are adjacent and the first node's successor's address when they are not, then that conditional would not be needed, because figuring out the second node's new successor is what (apparently) necessitates that conditional.
Second, I have the same question about the consecutive assignments to the same variables in the accepted answer as other commentators. I hope I am not being extremely dense here, but assigning different values to the same variable in sequence, unless perhaps in case of side-effects, to me just never seems to leave the variable with any other value than the last assignment, no matter what configuration of nodes I consider, and thus makes the previous assignments apparently redundant. If I am wrong about that and that approach would in fact solve this problem then I would have been able to eliminate the last conditional in the code below, which I was trying to get rid off when I first looked on the Internet for a solution to swapping nodes without special-casing adjacent nodes. I am not quite sure, but it sounded like Smashery purposefully left those repeated assignments out of logical rigor and to better illustrate the procedure - I may have misunderstood, though.
Third, on this and other sites I have often seen the statement from other answers repeated that it is better to swap the content of the nodes, rather than the pointers. Of course, in the case of simple integers, as in the examples so far, that does apparently yield shorter, simpler code. However, when we discuss linked lists with nodes containing integers it is usually as a stand-in for the backing data structure of a more complex and generic container. As such, I don't think swapping the contents of the nodes is really that easy, at least if the implementation of the data structure cannot make assumptions about the copy semantics of the container's items. Also, being able to swap around the contents of nodes like that implies to me that the linked list has ownership of the contents of those nodes, because otherwise code outside of the linked list's method might hold references to the objects in those nodes, whose values suddenly change underneath them.
I do admit, though, that this might depend on the semantics of the container. For an array, a swap method may be expected to change the value underneath references to a certain index of that array. That would mean that the references are not meant to refer to a specific object, but to a position in a container that one can index. If we consider a linked list as a means to only order a set of objects, which have their use outside of the linked list, a user would probably expect a swap operation to only exchange the position, not the contents.
Imagine, for example, that the linked list represents objects of type "car". Each car has an owner and that owner references their car through a pointer to it. Now suppose the linked list represents the order a set of cars are scheduled to be serviced for inspection at a car dealership. If we swapped the contents of two nodes, in order to exchange the schedule slots for two cars, and did it by exchanging their contents, then the servicing would in fact happen in the new, right order - but people would also end up suddenly owning different cars! (I wouldn't mind swapping with a Tesla, though, because I am only driving a Corolla.)
If the linked list was, as in the example of the array, based on indexing semantics then the position in the node might simply represent the order in which the cars are loaded onto a ship for transport. At this point, the cars don't have any owners and we really only care what slot they are in. Then, I suppose it really doesn't hurt to swap out cars, i.e. the contents of the objects referenced by the nodes.
Finally to the code. As I said above, I haven't been able to avoid the special-casing for adjacent nodes.
First, the definition of an auxiliary method:
int find_node(int v, node* root, node** n, node** pn) {
int i = 0;
for (*n = root; *n != NULL && (*n)->v != v; ++i) {
*pn = *n;
*n = (*n)->next;
}
return i;
}
This method finds a node by its value. The integer returned is the zero-based position (call it its index if you like) of the node in the linked list. I found detecting adjacency through position, rather than pointer comparisons, more readable. The start of the list is root. The method sets n to point to the node containing the passed value. In pn, the method stores the predecessor of n.
The following is the actual swap:
void swap_nodes(node **root, int v1, int v2) {
if (v1 == v2) return;
node *n1, *n2, *pn1, *pn2;
int p1 = find_node(v1, *root, &n1, &pn1);
int p2 = find_node(v2, *root, &n2, &pn2);
if (p1 > p2) {
std::swap(n1, n2);
std::swap(pn1, pn2);
std::swap(p1, p2);
}
if (p1 == 0) *root = n2;
else pn1->next = n2;
node* nn1 = n1->next;
n1->next = n2->next;
if (p2 - p1 > 1) {
n2->next = nn1;
pn2->next = n1;
} else {
n2->next = n1;
}
}
I'm sorry that I have changed the signature of the OP's method a bit. I found it more convenient to pass in the values of the nodes to swap, as opposed to node pointers. If you pass in node pointers to the respective nodes only, you would have to do another traversal to find the predecessors with this solution, which felt a bit awkward to me. If we cannot distinguish nodes by these values, e.g. values are not unique, we will need pointers to the nodes, though.
As with the explanation for find_node above, we first find the positions, nodes, and predecessors for the node values passed to swap_nodes through v1 and v2. The values for the first and second nodes are all swapped if the second node to swap appears before the first. It's not much code to do so, reduces special casing, and makes it a bit easier to visualize.
Now, we are left with just two more conditionals, neither of which seemed trivial to avoid. If the first node is at the head of the linked list, i.e. at position zero, the root needs to point to the second node. Otherwise, the first node's predecessor will point to the second node.
The previous value of the first node's successor needs to be remembered, in case the nodes are not adjacent. Then, the first node's successor is set to the current successor of the second node. This is the only change that applies to all cases: the new successor of the first node being the old successor of the second node is the only certainty and helpful to start off with in order to remember the pointer operations and their sequence when implementing this swap.
Last, if the positions of the nodes differ by more than one, they are not adjacent. Then, the second node's new successor becomes the first node's old successor - saved away above - and the second node's predecessor now points to the first node. If they are adjacent, there are no nodes between the nodes to swap that need updating, so simply linking the second node to the first is all that is left to do.