Deleting a node in the linklist - c++

Here is my code to delete all the nodes having the value passed in the argument.
typedef struct nodetype
{
int data;
struct nodetype * next;
} node;
typedef node * list;
void Linklist::deleteNode(list * head, int value)
{
list current = *head;
list previous = *head;
while(current != NULL)
{
if(current->data != value)
{
previous = current;
current = current->next;
}
else if (current->data == value)
{
previous->next = current->next;
delete current;
current = previous->next;
}
}
}
But here if all the elements in the linklist is say 2, then it should delete all the elements in the linklist and finally head should also become NULL so that if I pass this head to count the number of nodes in the list it should say that the list is empty and other similar operations.
According to my current implementation the head is not becoming NULL for the above mentioned case.
Please suggest the modification so that head should become NULL if the linklist has all the nodes with the same value passed in the function argument.

I modified my code as follows and its working file now
void Linklist::deleteNode(list *head, int value)
{
list * current = head;
list * previous = head;
bool flag = false;
while(*current != NULL)
{
if((*current)->data != value)
{
*previous = *current;
*current = (*current)->next;
}
else if ((*current)->data == value)
{
flag = true;
(*previous)->next = (*current)->next;
delete *current;
*current = (*previous)->next;
}
}
if(!flag)
cout<<"Element not found in the linklist\n";
cout<<"Count is "<<Linklist::count(*head)<<endl;
}

Related

C++ Need help on Remove Node function

I have stressed my head out the last few days to figure out how to get this remove() function to work. I'm still a student and data structure is no joke.
I really need help on how to get this function to remove a specific number on the list from user input. Doesn't matter what I try, it still could not work right.
For example, the list is: [1, 2, 3]
I want to delete number 2 on the list. I want the remove() function to traverse thur the list, if it found number 2, then delete number 2.
class SortedNumberList {
public:
Node* head;
Node* tail;
SortedNumberList() {
head = nullptr;
tail = nullptr;
}
void Insert(double number) {
Node* newNode = new Node(number);
if (head == nullptr) {
head = newNode;
tail = newNode;
}
else {
tail->SetNext(newNode);
tail = newNode;
}
}
// Removes the node with the specified number value from the list. Returns
// true if the node is found and removed, false otherwise.
bool Remove(double number) {
Node* temp = head;
if (temp == nullptr) {
return false;
}
if (head->GetData() == number) {
head = head->GetNext();
return true;
}
else{
while (temp != nullptr) {
Node* curNode = temp;
Node* preNode = nullptr;
preNode = curNode->GetPrevious();
temp = temp->GetNext();
if (curNode->GetData() == number) {
preNode = curNode->GetNext();
return true;
}
delete curNode;
}
}
delete temp;
}
};
class Node {
protected:
double data;
Node* next;
Node* previous;
public:
Node(double initialData) {
data = initialData;
next = nullptr;
previous = nullptr;
}
Node(double initialData, Node* nextNode, Node* previousNode) {
data = initialData;
next = nextNode;
previous = previousNode;
}
Edit: I'm able to solve my own issue, thank you everyone.
bool Remove(double number) {
// Your code here (remove placeholder line below)
Node* temp = head; //Make a temporary node point to head.
if (temp == nullptr || head == nullptr) { //if user don't provide input, return false.
return false;
}
if (head->GetData() == number) { //If number need to delete is at head.
head = head->GetNext();
return true;
}
else {
while (temp != nullptr) { //Travese temp node throught out a list.
Node* curNode = temp->GetNext(); //Make a current node point at temp next.
Node* preNode = temp;
Node* sucNode = curNode->GetNext();
if(curNode->GetData() == number) { //Delete a node if number is found on the list
if (curNode->GetNext() == nullptr) { //Delete at tail.
preNode->SetNext(nullptr);
tail = preNode;
delete curNode;
return true;
}
if (curNode->GetNext() != nullptr) {
preNode->SetNext(sucNode);
sucNode->SetPrevious(preNode);
delete curNode;
return true;
}
}
temp = temp->GetNext();
}
}
return false;
}
};
You should make Node a friend class of SortedNumberList or define former inside the later class which simplifies the code somewhat. It's personal preference but it leads to less unnecessary boilerplate code (getters and setters).
In a double linked list you do not need to keep track of the last as you do need on single linked lists because you have both pointers available.
The quest is just a matter of iterating to find the value, taking care to cut it early when we pass the mark since it is a sorted list.
Then delete the object and update the link pointers.
bool Remove(double number) {
// Loop through the entire list
Node* temp = head;
while ( temp != nullptr) {
// There is no point looking forward if the list is sorted
if (temp->data > number ) return false;
// Compare to find
if (temp->data == number) {
// Get the pointers so we can delete the object
Node* prev = temp->previous;
Node* next = temp->next;
// Delete object
delete temp;
// Update previous pointers
if ( prev==nullptr ) {
head = next;
} else {
prev->next = next;
}
// Update next pointers
if ( next==nullptr ) {
tail = prev;
} else {
next->previous = prev;
}
// Indicate success
return true;
}
}
// We iterated to the end and did not find it
return false;
}

Deleting node in a double linked list is not working

This is a basic function that takes an iterator position and deletes the node in this position but it gives me a runtime error. what am i doing wrong?
iterate erase(iterate position)
{
iterate i;
Node<T>* temp = head;
if (head == NULL) {
cout << "empty list" << endl;
}
else if (position.pointer == head) {
head = temp->next;
temp->next->previous = NULL;
delete position.pointer;
}
else {
while (temp != NULL) {
if (temp == position.pointer->previous) {
temp->next = position.pointer->next;
temp->next->previous = temp;
i.pointer = temp->next;
delete position.pointer;
return i;
}
}
}
Your function is lacking adequate return statements. There are multiple flows that can cause the function to exit, but only one of them has a return statement. So the return value will largely be indeterminate, causing undefined behavior for any caller that tries to use the return value.
In any case, your while loop iterates forever, because you are not updating temp on each iteration of the loop. You also have a NULL pointer dereference if position is pointing at the last node in the list, as you are not checking the new temp->next for NULL before accessing temp->next->previous.
But, you really don't need the while loop at all. The thing about a double-linked list is that, given any node in the list, you have direct access to the nodes that are surrounding it on both sides. So there is no need to iterate the list hunting for nodes.
Try something more like this instead:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *next = temp->next;
Node<T> *previous = temp->previous;
if (next) next->previous = previous;
if (previous) previous->next = next;
if (temp == head) head = next;
//if (temp == tail) tail = previous;
delete temp;
iterate i;
i.pointer = next;
return i;
}
Alternatively:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *dummy; // <-- only if no tail ...
Node<T> **previous = (temp->next) ? &(temp->next->previous) : &dummy/*&tail*/;
Node<T> **next = (temp->previous) ? &(temp->previous->next) : &head;
*previous = temp->previous;
*next = temp->next;
delete temp;
iterate i;
i.pointer = *next;
return i;
}

Linked list head pointer not getting updated when called by reference

I have written two functions to insert nodes in a Linked List. While one function (insertNth) updates the head pointer, the second one (sortedInsert) does not update the head pointer across function calls. The push function is taking a reference to the head pointer.
struct node
{
int data;
node *next;
};
void printList(node *head)
{
node *current = head;
while(current!=NULL)
{
cout<<current->data<<" ";
current = current->next;
}
}
void push(node* &head, int data)
{
node *newNode = new node();
newNode->data = data;
newNode->next = head;
head = newNode;
}
void insertNth(node *&head, int index, int val)
{
node *current = head;
int cnt = 0;
while(current!=NULL)
{
if(cnt == index)
{
if(cnt==0)
{
push(head, val);
}
else
{
push(current->next, val);
}
}
current=current->next;
cnt++;
}
}
void sortedInsert(node *head, int val)
{
node *current = head;
if(head != NULL && val < head->data)
{
node *newNode = new node();
push(head,val);
return;
}
while(current!=NULL)
{
if(current->data < val && current->next->data > val)
{
push(current->next, val);
return;
}
current = current->next;
}
}
int main()
{
node *head;
push(head, 3);
cout<<"\n";
printList(head);
cout<<"\nInsertNth: ";
insertNth(head,0, 2);
printList(head);
cout<<"\nsortedInsert: ";
sortedInsert(head, 1);
printList(head);
return 0;
}
I'm getting following as output:
3
InsertNth: 2 3
sortedInsert: 2 3
Why is the third line not printing 1 2 3?
//
Update
//
The correct SortedInsert is as follows:
void sortedInsert(node *&head, node *newNode)
{
node *current = head;
if(head == NULL || newNode->data < head->data)
{
newNode->next = head;
head = newNode;
return;
}
while(current!=NULL && current->next != NULL)
{
if(current->data < newNode->data && current->next->data > newNode->data)
{
newNode->next = current->next;
current->next = newNode;
return;
}
current = current->next;
}
if(current->next == NULL)
{
current->next = newNode;
newNode->next = NULL;
}
}
A sample was requested. Note that I did it as a template, but you could skip the template business and instead of a T* you can use struct node *. It's not general purpose, but might be easier to understand.
template <class T>
class MyLinkedList {
class Entry {
public:
Entry * previous;
Entry * next;
T * node;
}
Entry * head;
Entry * tail;
void push(T * nodeToPush) { pushBefore(head, nodeToPush); }
void insertNth(int whereToInsert, T * nodeToInsert) {
... find the nth Entry pointer
pushBefore(head, nodeToPush);
}
private:
void pushBefore(Entry *entry, T * nodeToPush) {
Entry *newEntry = new Entry();
newEntry->node = nodeToPush;
if (entry != NULL) {
newEntry->previous = entry->previous;
}
newEntry->next = entry;
entry->previous = newEntry;
if (head == entry) {
head = newEntry;
}
if (tail == NULL) {
tail = newEntry;
}
}
// Other methods as necessary, such as append, etc.
}
Other than passing in a pointer to the objects you're inserting into your linked list, at no point do you have to pass pointers around in a fashion where your methods are also performing side effects on those pointer. The class should know how to manage a class, and no weird passing of variables all over.
Performing side effects on your arguments should be done with GREAT caution. If you're passing an object to a method, then it's fair to manipulate the object. But I really don't like passing pointers and having methods modify the pointers themselves.
That IS going to lead to (at best) confusion.
Note: I did NOT test this code. It might not quite be perfect.

algorithm for finding a node in a linked list

what is the algorithm used to write Snode* find and set& operator=( set &rhs) I just can't understand these two. I can read the code but I can't figure out why are they there. I can't understand the steps of the used algorithm.
Things I already figured out:
1. Snode is a function that gets a value and returns the node with the same data.but what do prev and previous do and what is **previous and why ahould we create a pointer to a pointer?
2. set& operator= is for overriding the = operator. but I can't understand what does it do after overriding.and why should we swap the heads of temp and rhs sets.
here's the code:
#include <iostream>
using namespace std;
struct Snode //Snode class defines a node in a list
{
char data;//a node includes a character
int count;//an integer to count the occurrence
Snode *next = NULL;//and a pointer to the next node
Snode(char data, Snode* next) : data(data), next(next) {}
};
class set
{
private:
Snode *head;//first node in the list
Snode *tail;//last node of the list
public:
set() : head(NULL), tail(NULL)
{
}
set( set &src) : head(NULL), tail(NULL)//copy constructor method
{
Snode *temp = src.head;//set head of the second list as temp to travers
while (temp)//untill the end of the list
{
// insert(temp->data);
Snode *newNode = new Snode(temp->data,NULL);//create a new node with the same data and count
newNode->count = temp->count;
//now puts it in the right place
if (!head)//if head = NULL (if sset is empty)
head = newNode;//set the new node as the first node
if (tail)//if tail != NULL (if set isn't empty)
tail->next = newNode;//set new node as the next node of current tail, so it'll be the tail
tail = newNode;
temp = temp->next;//does the same thing for all the nodes of the second list
}
}
~set()//destructor method
{
Snode *temp = head;
while (temp)//traverse the list and delete each node
{
Snode *next = temp->next;
delete temp;
temp = next;
}
}
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
}
return *this;
}
bool isAvailable(char value)//checks if any node with the same data exists or not
{
return (find(value) != NULL);//if find function can't find any, there's no same node
}
Snode* find(char value, Snode **previous = NULL)
{
if (previous)
*previous = NULL;
Snode *temp = head;
Snode *prev = NULL;
while (temp)
{
if (temp->data == value)
{
if (previous)
*previous = prev;
return temp;
}
temp = temp->next;
}
return NULL;
}
bool isFirst(char value)
{
return ((head) && (head->data == value));//if head's data is equal to value returns true
}
bool isLast(char value)
{
return ((tail) && (tail->data == value));//if tail's data is equal to value returns true
}
void display()
{
Snode *temp = head;
while (temp)
{
cout << temp->data << " " << temp->count+1 << "\n";
temp = temp->next;
}
}
void insert(char value)//to insert a new value
{
Snode *temp = find(value);//if a node with the same data alreay exists
if (temp)
temp->count += 1;//increase the count by one
else
{
temp = new Snode(value,NULL);//if if a node with the same data doesn't exist
if (!head)//if list is empty
head = temp;
if (tail)//if list is not empty
tail->next = temp;
tail = temp;
}
}
int count(char value)//count the nodes by the counter temp
{
Snode *temp = find(value);//travers the set
return (temp) ? temp->count : 0;//if the list is empty return 0, else return the counter
}
void deleteFirst()//deletes the first node
{
if (head)//if list isn't empty
{
Snode *temp = head;
head = head->next;//move the head forward
if (tail == temp)//if loop faced the tail
tail = NULL;
delete temp;//delete the data
}
}
void deleteLast()//delete the last node
{
if (head)
{
Snode *last = head;
Snode *previous = NULL;
while (last->next)//move forward untill the node before the last one
{
previous = last;
last = last->next;
}
if (previous)//at the end of the list
previous->next = NULL;
tail = previous;
if (head == last)//if there's only one node
head = NULL;
delete last;
}
}
void remove(char value)//remove the node with the same data as the entry
{
Snode *previous;
Snode *temp = find(value, &previous);
if (temp)
{
if (temp->count > 1)
temp->count -= 1;
else
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
if (tail == temp)
tail = previous;
delete temp;
}
}
} };
As you have guessed, find tries to locate a Snode containing the required character. If only that is required, you can ignore the previous parameter (it will be NULL), and previous/prev processing will just be useless.
But find is used in remove... In order to remove a node in a singly linked list, you must have the previous one point to the next one. So you must browse the list keeping a track of the previous node. That is exactly the way it is used in remove with:
if (previous)
previous->next = temp->next;
The assignment operator uses a close variant of the copy and swap idiom. But as the destructor only uses the head member, only that member is swapped: that will be enough to have the destructor of temp to destroy all nodes of the original list.
Simply tail should be set in this even if it is useless to set it in tmp. A correct implementation could be:
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
tail = temp.tail; // no need for a full swap here
}
return *this;
}

Inserting into a Doubly Linked List

I am trying to create a doubly linked list container for a project. I cannot use any std containers. The doubly linked list has to be sorted. Here is my code so far:
#include <iostream>
using namespace std;
template <typename T>
class dll {
private:
struct Node {
Node* prev;
Node* next;
T data;
};
Node* head;
Node* tail;
public:
dll();
~dll();
void insert(T value);
bool empty() const { return head == tail; };
};
template <typename T> dll<T>::dll() {
head = nullptr;
tail = head;
}
template <typename T> dll<T>::~dll() {
delete[] head;
}
template <typename T> void dll<T>::insert(T value) {
Node *node = new Node;
node->data = value;
// Case 1: There are no nodes yet
if (head == nullptr) {
node->prev = nullptr;
node->next = nullptr;
head = node;
tail = head;
}
else {
// Case 2: There is more than one node
Node *curr = head;
if (curr->next != nullptr)
{
while (curr->next) {
// If the value is less than the current value
if (value < curr->data) {
Node *temp = new Node;
temp->data = curr->data;
temp->next = curr->next;
temp->prev = curr->prev;
node->next = temp;
node->prev = temp->prev;
curr->prev = node;
}
curr = curr->next;
}
}
// Case 3: There is only one node
else {
node->prev = head;
node->next = nullptr;
tail = node;
}
}
}
int main() {
dll<int> list;
list.insert(10);
list.insert(20);
list.insert(15);
}
The problem I am having is in my insert function. I am using the debugger and stepping into the code at the line: list.insert(10);.
It correctly goes into the first case where head == nullptr and creates the Node.
When I step into the next line of code (list.insert(20) ), it creates a node with this line: Node *node = new Node;
But it is creating the node with the memory address that head is pointing to.
I put a watch on the head variable and the node variable and the memory addresses were the same.Basically it is creating the same Node as it did for the last insertion.
I don't know how to get the line: Node *code = new Node; to create something new. Am I using the new keyword wrong here?
To make the initialization of Node easier, let's add a reasonable constructor that initializes prev and next members to null. That makes things easier for later code.
struct Node {
Node* prev;
Node* next;
T data;
Node() : prev(nullptr), next(nullptr)
{
}
};
There's always four cases to be aware of in a linked list problem. Some of which you got. Inserting into an empty list. Inserting at the front of the list, inserting at the end of the list, and the middle.
template <typename T> void dll<T>::insert(T value) {
Node *node = new Node;
node->data = value;
// Case 1: There are no nodes yet
if (head == nullptr) {
head = node;
tail = head;
return;
}
// case 2 - inserting at the head of the list
if (node->data < head->data)
{
node->next = head;
head = node;
return;
}
// case 3 - inserting at the end of the list
if (node->data >= tail->data)
{
node->prev = tail;
tail->next = node;
tail = node;
return;
}
// general case - inserting into the middle
Node* probe = head;
while (probe && (node->data >= probe->data))
{
probe = probe->next;
}
if (probe)
{
node->next = probe;
node->prev = probe->prev;
probe->prev->next = node;
probe->prev = node;
return;
}
// error - we shouldnt' reach this point. If we did, it meant the list was out of order to begin with.
return;
}
First of all the destructor is invalid. This statement
delete[] head;
means that head is an array. However head is not an array. It is a pointer to a single object of type Node. You have to delete all nodes of the list in the destructor. The destructor can look the following way
template <typename T>
dll<T>::~dll()
{
while ( head )
{
Node *tmp = head;
head = head->next;
delete tmp;
}
}
As for the method insert then it can look very simply. For example
template <typename T>
void dll<T>::insert( const T &value )
{
Node *current = head;
Node *previous = nullptr;
while ( current && !( value < current->data ) )
{
previous = current;
current = current->next;
}
Node *node = new Node { previous, current, value };
if ( previous == nullptr ) head = node;
else previous->next = node;
if ( current == nullptr ) tail = node;
else current->prev = node;
}
And there is no any need and reason to add a constructor to structure Node. It is better when it is an aggregate.
Here is a test program
#include <iostream>
template <typename T>
class dll
{
private:
struct Node
{
Node *prev;
Node *next;
T data;
};
Node *head;
Node *tail;
public:
dll();
~dll();
void insert( const T &value);
bool empty() const { return head == tail; };
void print() const;
};
template <typename T>
dll<T>::dll()
{
head = tail = nullptr;
}
template <typename T>
dll<T>::~dll()
{
while ( head )
{
Node *tmp = head;
head = head->next;
delete tmp;
}
}
template <typename T>
void dll<T>::insert( const T &value )
{
Node *current = head;
Node *previous = nullptr;
while ( current && !( value < current->data ) )
{
previous = current;
current = current->next;
}
Node *node = new Node { previous, current, value };
if ( previous == nullptr ) head = node;
else previous->next = node;
if ( current == nullptr ) tail = node;
else current->prev = node;
}
template <typename T>
void dll<T>::print() const
{
for ( Node *current = head; current; current = current->next )
{
std::cout << current->data << ' ';
}
}
int main()
{
dll<int> list;
list.insert( 10 );
list.insert( 20 );
list.insert( 15 );
list.print();
std::cout << std::endl;
return 0;
}
The output is
10 15 20