C++ Need help on Remove Node function - c++

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;
}

Related

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;
}

Unable to create or return Reversed Linked list

Here using the function returnReverseLinkedList I am returning the reversed linked list of the given linked list. But the problem with this approach is that i lose the original linked list. So I make another fucntion called createReversedLinkedList to make a copy of the original linked list and reverse the copy and maintain possession of both.
unfortunately createReversedLinkedList is giving Runtime error.
obviously my end goal is to check if the given linked list is palindrome or not. This issue is just a stepping stone.
Could someone tell me why?
//Check if a linked list is a palindrome
#include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
node(int data)
{
this->data = data;
this->next = NULL;
}
};
node *returnReverseLinkedList(node *head)
{
// Will Lose original Linked List
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return head;
node *prev = NULL;
node *curr = head;
node *tempNext = head->next;
while (tempNext != NULL)
{
curr->next = prev;
prev = curr;
curr = tempNext;
tempNext = tempNext->next;
}
curr->next = prev;
return curr;
}
node *createReversedLinkedList(node *head)
{
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return NULL;
else
{
node *temp = head;
node *newHead = NULL;
node *newTail = NULL;
while (temp != NULL)
{
node *newNode = new node(temp->data);
if (newHead == NULL)
{
newHead = newNode;
newTail = newNode;
}
else
{
newTail->next = newNode;
newTail = newNode;
}
}
return returnReverseLinkedList(newHead);
}
}
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head);
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false;
cout << "debug 2" << endl;
original = original->next;
reverse = reverse->next;
}
return true;
}
// #include "solution.h"
node *takeinput()
{
int data;
cin >> data;
node *head = NULL, *tail = NULL;
while (data != -1)
{
node *newnode = new node(data);
if (head == NULL)
{
head = newnode;
tail = newnode;
}
else
{
tail->next = newnode;
tail = newnode;
}
cin >> data;
}
return head;
}
void print(node *head)
{
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
int main()
{
node *head = takeinput();
node *revese2 = createReversedLinkedList(head);
print(revese2);
// bool ans = check_palindrome(head);
// if (ans)
// cout << "true";
// else
// cout << "false";
// return 0;
}
As asked by the OP, building a reversed linked is simply done by building as you would a stack (e.g LIFO) rather than duplicating the same original forward chain. For example:
node *createReversedLinkedList(const node *head)
{
node *newHead = NULL;
for (; head; head = head->next)
{
node *p = new node(head->data)
p->next = newHead;
newHead = p;
}
return newHead;
}
Note we're not hanging our copied nodes on the tail of the new list; they're hanging on the head of the new list, and becoming the new head with each addition. That's it. There is no need to craft an identical list, then reverse it; you can reverse it while building the copy to begin with.
A note on the remainder of your code. You have a dreadful memory leak, even if you fix the reversal generation as I've shown above. In your check_palindrome function, you never free the dynamic reversed copy (and in fact, you can't because you discard the original pointer referring to its head after the first traversal:
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head); // only reference to reversed copy
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false; // completely leaked entire reversed copy
original = original->next;
reverse = reverse->next; // lost original list head
}
return true;
}
The most obvious method for combating that dreadful leak is to remember the original list and use a different pointer to iterate, and don't leave the function until the copy is freed.
bool check_palindrome(const node *head)
{
bool result = true;
node *reverse = returnReverseLinkedList(head);
for (node *p = reverse; p; p = p->next, head = head->next)
{
if (p->data != head->data)
{
result = false;
break;
}
}
while (reverse)
{
node *tmp = reverse;
reverse = reverse->next;
delete tmp;
}
return result;
}

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.

Recursive Reverse Single Linked List

I am trying to just write a basic function that reverses a singly-linked list which is recursive. I was wondering if i tackled this in the right approach? Maybe someone can give me some pointers.
void reverse(Node*& p) {
if (!p) return;
Node* rest = p->next;
if (!rest) return;
reverse(rest);
p->next->next = p;
p->next = NULL;
p = rest;
}
That's not the most efficient way, but to do it, you can call the reverse method with the "next" pointer until there is no next. Once there, set next to previous. After returning from the recursion, set next to previous. See the recursive version here for an example. From the link:
Node * reverse( Node * ptr , Node * previous)
{
Node * temp;
if(ptr->next == NULL) {
ptr->next = previous;
previous->next = NULL;
return ptr;
} else {
temp = reverse(ptr->next, ptr);
ptr->next = previous;
return temp;
}
}
reversedHead = reverse(head, NULL);
This might be helpful
List
{
public:
.....
void plzReverse()
{
Node* node = myReverse(head);
node->next = NULL;
}
private:
Node * myReverse(Node * node)
{
if(node->next == NULL)
{
head = node;
return node;
}
else
{
Node * temp = myReverse(node->next);
temp ->next = node;
return node;
}
}
}
Another solution might be:
List
{
public:
.....
void plzReverse()
{
Node* node = myReverse(head, head);
node->next = NULL;
}
private:
Node * myReverse(Node * node, Node*& rhead)
{
if(node->next == NULL)
{
rhead = node;
return node;
}
else
{
Node * temp = myReverse(node->next,rhead);
temp ->next = node;
return node;
}
}
}
This is what you need:
Node* reverse(Node* p) {
if (p->next == NULL) {
return p;
} else {
Node* t = reverse(p->next); // Now p->next is reversed, t is the new head.
p->next->next = p; // p->next is the current tail, so p becomes the new tail.
p->next = NULL;
return t;
}
}
The recursive solution can look quite pretty, even in C++:
Node* reverse(Node* pivot, Node* backward = 0) {
if (pivot == 0) // We're done
return backward;
// flip the head of pivot from forward to backward
Node* rest = pivot->next;
pivot->next = backward;
// and continue
return reverse(rest, pivot);
}
Most C++ compilers do tail call optimization so there's no reason to believe this to be less efficient than an iterative solution.
Here is the solution that preserves return value as void.
void reverse(Node*& p) {
if (!p) return;
Node* rest = p->next;
if (!rest) {
rest = p;
return;
}
reverse(rest);
p->next->next = p;
p->next = NULL;
p = rest;
}
linkedList *reverseMyNextPointer(linkedList *prevNode, linkedList *currNode)
{
linkedList *tempPtr;
if(!currNode)
return prevNode;
else
{
tempPtr = currNode->next;
currNode->next = prevNode;
return reverseMyNext(currNode,tempPtr);
}
}
head = reverseMyNextPointer(nullptr,head);

Deleting a node in the linklist

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;
}