Deleting a linked list with specified data recursively - c++

I want to delete a linked list recursively. I figured how to do this iteratively but I'm curious on how to do this. So far I have:
void deleteNodeRecursively(LinkedList *list, int value){
Node *curr=list->head;
if (list->head==NULL){
return;
}
else if (list->head->data==value){
Node *x=list->head->next;
delete list->head;
list->head=x;
}
else{
LinkedList *newlist;
newlist->head=list->head->next;
deleteNodeRecursively(newlist,value);
}
}
Where I defined
struct LinkedList{
Node *head;
};
struct Node{
int data;
Node *next;
};
I can remove the head if need be, but I can't figure out how to remove the body or tails and then correctly stitch up the list, let alone do it recursively. How do I proceed? Why won't this work?
EDIT: Removed question marks and replaced with code that I thought would work.

Assuming you have a "correct" constructor and destructor for your Node data.
You would have to track address of the deletion, for which you could pass a double pointer or a reference to pointer.
void deleteNodeRecursively(Node** list, int value){
// ^^^ double pointer to track address withing recursive call
Node *curr= *list ;
if (curr ==NULL){ // Base case for recursion
return;
}
else if ( curr->data==value){ // If node to be deleted is found
*list = curr->next; // Update the address for recursive calls
delete curr; // Delete this current "got" node
}
// Else simple recurse into
deleteNodeRecursively( &(*list)->next, value );
}
Note: This implementation will delete all nodes with data that matches value .

Related

Why we initialize the next pointer of Linked List as NULL before deletion

Why we initialize the next pointer of Linked List as NULL before deletion
we move our head to the next node during deletion and we free the memory of the first node, so why we need to initialize the next pointer of deleted node as NULL before deletion.
without it, the code runs without any issues.
Is this dangling pointer will create a issue? please throw some light in it
class Node
{
public:
int data;
Node* next;
Node(int d) //construtor for storing the value in nodes
{
this->data=d;
this->next=NULL;
}
};
void DeleteAt(int position,Node* &head,Node *&tail)
{
if(position ==1)
{
Node* temp=head;
head=temp->next;
temp->next=NULL;
delete temp;
}
else
{
Node *curr=head;
Node *prev=NULL;
int cnt=1;
while(cnt<position)
{
prev=curr;
curr=curr->next;
cnt++;
}
// if delete at tail is called ,for updation of tail,
//if required
if(curr->next==NULL)
{
tail=prev;
}
prev->next=curr->next;
curr->next=NULL;
delete curr;
}
}
You don't need to do this, it's just to help you while you're learning. It's common for teachers to do this to help avoid use-after-frees. This way, it's much more obvious you have a problem, because if you accidentally try to use the node you just deleted, you'll probably get a segfault.

function with return type node* in conjunction with OOP in c++

I need to write a program that takes an instance of a linear linked list and removes all of the items in the list except for the last two items. I'm doing this in c++ using classes, so I'll have 3 files: main.cpp, list.h, and list.cpp. There can be no loops: I can use multiple functions but the traversal part has to be recursive.
I thought about it and what I concluded is this: I'll have to have one public function that I can call from main which will take no arguments, called void lastTwo(). I'll have another private function called node* lastTwo(node *& current, node *& tail) which will be called by lastTwo(), and it will traverse the list recursively and delete the nodes it touches until it reaches the second to last node in the list, and then it will return the address of that node.
Then, when it returns the address of the second to last node in the list, the public function lastTwo() will catch that address and set head equal to it.
The problem I'm having is that I need to do this in vi and compile and run from the command line, and I'm getting a segmentation fault even though I drew a pointer diagram and can't find a problem with my code.
I'm working on this on the student server at my university, and all of the implementation of the data structure except for these two functions have been written by my instructors, so they're all solid. Also, every time you run the a.out file, they've written it to generate a new, random, non-empty linked list, of at least 5 nodes.
I think the problem is related to the function having the return type "node*" , because I tried doing this in visual studio as well and it wouldn't let me have functions of type node*. But, I know that when you don't use classes and just put everything in one file, functions of type node* work.
Here is my list.h:
#include<iostream>
struct node
{
int data;
node* next;
};
class list
{
public:
// these functions were already written by the school and included in the .o file
list();
~list();
void build();
void display();
// my functions
void lastTwo();
private:
node* head;
node* tail;
node* lastTwo(node *& current, node *& tail);
}
And list.cpp:
void list::lastTwo(){
node* current = head;
node * newHead = lastTwo(current, tail);
head = newHead;
delete newHead;
head->next = tail;
}
node* lastTwo(node *& current, node *& tail){
if(current->next == tail){
return current;
}
else if(current->next != tail){
node* temp = current;
current = current->next;
temp->next = NULL;
delete temp;
lastTwo(current, tail);
}
return NULL;
}
Any ideas on what might be the problem, and what the correct way to do this is, would be really appreciated! Thank you
Your problem happens when your recursion unwinds. Most of the calls to lastTwo happen in the else if. That base case is the if which returns current, but the call to lastTwo which triggered the base case is always going to return NULL when the else if ends.
Imagine this is your stack when the base case is reached:
lastTwo // Base case, returns current, but the call below this doesn't do anything with it.
lastTwo // returns null
...
lastTwo // returns null
That NULL is used by the other lastTwo and you get your seg fault.
You might use the following:
void list::lastTwo() {
// Stop work with less than 2 items
if (head == nullptr // 0 items
|| head == tail // 1 item
|| head->next == tail) { // 2 items
return;
}
// pop_front()
auto* next = head->next;
delete head;
head = next;
// loop
lastTwo();
}

double linked list head dereferenced is null

my head pointer is supposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explain how I could point the head node pointer?
void dlist::push_front(int value) {
node *p = new node();
node *tempH = head();
tempH->next = p; //break
/***********************************************************
my head pointer is suposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explane how I could point the head node pointer?
************************************************************/
p->value = value;
p->next = tempH->next;
p->prev = tempH;
p->next->prev = p;
p->prev->next = p;
}
#pragma once
#include <ostream>
class dlist {
public:
dlist() {}
// Implement the destructor, to delete all the nodes
//~dlist();
struct node {
int value;
node* next;
node* prev;
};
node* head() const { return _head; }
node* tail() const { return _tail; }
void push_front(int value);
private:
node* _head = nullptr;
node* _tail = nullptr;
};
in your list constructor, simply set the head pointer to null.
dlist::dlist() {
_head = nullptr;
}
Further, if you end up removing the LAST item in your list, you will need to also make _head = nullptr;
Be sure to check if the head is null before dereferencing.
if(_head == nullptr){
_head = new node(...);
}
Your insert function will be responsible for assigning the first node to the head, in the event that you're adding to an uninitialized list.
If your list needs to be sorted, you will need to account for the head changing in the event that the new node should precede the head node.
The most practical solution here is to just use sentinel nodes for your head and tail. Or, just one sentinel node, that stands in for both. The sentinel nodes' elements can just be left uninitialised, you only need those nodes for the next and prev pointers they contain. To test if you've reached the end of the list, instead of testing for a null pointer, you test whether the pointer points to the sentinel node.
You can just use normal nodes as your sentinels if you expect your list elements to be small, or your lists to be very large. You waste a bit of memory on space for elements that won't be used, but it's probably not a big deal. If you really care about memory efficiency (say, you're writing a library), you can have something like this:
template<typename T> class dlist {
struct node_header {
node_header* next;
node_header* prev;
};
struct node : public node_header {
T element;
};
// Convert a node_header pointer to a node pointer
node* node_from_header(node_header* p) {
return static_cast<node*>(p);
}
};
With this approach, your sentinel node is a node_header and all your actual, element-containing nodes are nodes. Your internal algorithms all work on node_headers, until you need to actually retrieve the element of a node, at which point you use node_from_header() to retrieve the full, element-containing node.
If you absolutely want to not use sentinel nodes, you'll have to rewrite your code to directly use the head pointer, rather than retrieving it through a function, and add special-case code for handling a null head pointer. It's not a pretty option.

Deleting first node of linked list (C++)

I want to know whether this code deletes the first node correctly or should I necessarily pass list's head as a pointer?
void List::deleteFirst()
{
temp = head;
head = head->next;
delete temp;
}
This is the class List
class List
{
private:
struct node
{
int data;
node * next;
};
node * head;
node * curr;
node * temp;
public:
//List();
//void AddNode(int addData);
//void DeleteNode(int delData);
void deleteFirst();
//void PrintList();
};
This will work, bit only if:
Your Nodes are allocated using new
You ensure that head always points to a valid node (the list is not empty).
Otherwise, you will cause undefined behavior.
But you really shouldn't store temp as a member variable, it should be a local variable instead.
The same goes for the curr variable, make sure it really needs to be a member.
Also, if you delete an object (e.g. your node), all remaining pointers to it become invalid, so be careful that you don't try to access it afterwards, for ex. through the curr* pointer.
Yup that will delete the the data pointed to by the original value of head.

Can we delete the last node of a Single Linked list if we only know the address of last node

// Variables
typedef struct node
{
int value;
struct node *next;
}mynode;
// Globals (not required, though).
mynode *head, *tail, *temp;
// Functions
void add(int value);
// Function to add new nodes to the linked list
void add(int value)
{
temp = (mynode *) malloc(sizeof(struct node));
temp->next=(mynode *)0;
temp->value=value;
if(head==(mynode *)0)
{
head=temp;
tail=temp;
}
else
{
tail->next=temp;
tail=temp;
}
}
// The main() function
int main()
{
head=(mynode *)0;
// Construct the linked list.
add(1);
add(2);
add(3);
return(0);
}
If I only have a pointer to a node, whose value is 3(The Last node as seen in the aforementioned code) , Can we delete it and make a node whose value is 2(aforementioned code) as the last node.
No you can not. Unless you have some reference to previous node. like head pointer. If you have other reference than its pretty much easier. In fact if you don't have any pointers you will loose the list itself
No, but if you know what you are doing, you can modify the last node in-place. Deleting the last node requires access to the second-to-last node, and specifically its link to the last node.
The answer is no.
You can call free on that pointer to the last node, but that just means that the memory occupied by that node is no longer claimed. The data will most likely stay there unchanged for a while. And that means that the next-to-last node's pointer to it is still valid, even though it should not be.
To delete the node in a way that is meaningful to the list, that pointer contained in the next-to-last node has to be nullified. And that can't be done unless that next-to-last node can be accessed, either by a direct pointer to it, or by traversing the list from a preceding node.
You can use a doubly linked list to access the previous node. Or iterate through the entire list.
Yes you can.. Try the following code:
void deleteNode()
{
mynode *temp1;
for(temp1 = head; temp->next!= tail; temp1 = temp1->next);
tail = temp1;
free(tail->next);
}
It will delete the last node.