Linked Lists remove function in c++ - c++

I am trying to finish up an assignment regarding linked lists in c++ but my remove function seems to be crashing the app every time I try to use it. I've tried a few different things but I seriously don't know what's wrong. For example if I only have one item in the list and try to remove it it crushes same goes for any other case. If anyone knows what's wrong please help :)
template <class T>
Error_code List<T>::retrieve(string fn, T& item)
{
if (empty()) return underflow;
Node<T>* temp = head;
while (temp->entry.FlightNO.compare(fn) != 0) {
if (temp->next == NULL)
return not_found;
temp = temp->next;
}
item = temp->entry;
return success;
}
template <class T>
Error_code List<T>::remove(T& item)
{
Node<T>* current = head;
Node<T>* search = new Node<T>(item);
if (head == search) {
head = head->next;
return success;
}
else {
Node<T>* previous = current;
current = current->next;
if (current->next == NULL) {
delete current;
return success;
}
while (current != search)
{
previous = current;
current = current->next;
}
previous->next = current->next;
return success;
}
}
This is my code, the first function is to retrieve the item and check if it actually exists, then the second is the remove which doesn't work

Everything what was mentioned in the comments is on point. However you came here looking for an answer, so here you go:
template <class T>
Error_code List<T>::remove(T& item)
{
Node<T>* current = head;
Node<T>* search = new Node<T>(item); // <--- why?
//if (head == search) { //<-- always false
// head = head->next;
// return success;
//}
Node<T>* previous = current;
current = current->next;
if (current->next == NULL) {
delete current;
return success;
}
while (current != search) // <--- fails here, this is always true (you are comparing pointers, not objects)
{
previous = current;
current = current->next; // <--- because this loop is always true and you have a nullptr terminated list then this will segfault with RAV
}
previous->next = current->next;
return success;
}
}
EDIT: Just to clarify what causes the segfault, at the "end of the loop" you eventually call
nullptr->next;

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

c++ replace values in linked list by changing pointers

Having a problem with linked list. Need to create a method, which will replace data in list, by not creating a new element but by changing pointers. For now I have such method:
void replaceValues(Node* head, int indexOne, int indexTwo)
{
Node* temporaryOne = NULL;
Node* temporaryTwo = NULL;
Node* temp = NULL;
Node* current = head;
int count = 0;
while (current != NULL) {
if (count == indexOne)
{
temporaryOne = current;
}
else if (count == indexTwo)
{
temporaryTwo = current;
}
count++;
current = current->next;
}
current = head;
count = 0;
while (current != NULL) {
if (count == indexOne)
{
head = temporaryTwo;
}
else if (count == indexTwo)
{
head = temporaryOne;
}
count++;
current = current->next;
}
}
I am sure, that exists a more simpler way, how to do it, but I don't fully understand, how it works...
Thanks in advance for help.
I assume that with "replace" you actually mean "swap"/"exchange".
Some issues:
The argument head should be passed by reference, as one of the nodes to swap may actually be that head node, and then head should refer to the other node after the function has done its job.
The node before temporaryOne will need its next pointer to change, so you should stop your loops one step earlier in order to have access to that node and do that.
In some cases head may need to change, but this is certainly not always the case, so doing head = temporaryOne or head = temporaryTwo is certainly not right. In most cases you'll need to link to the swapped node from the preceding node (see previous point).
The next pointer of the node that is swapped will also need to change, as the node that follows it will be a different one than before.
As mentioned already in comments, it is advised to split the task into removals and insertions, as the fiddling with next pointers can get confusing when you try to cover all possible cases, notably making the distinction between the case where the two nodes are adjacent and when they are not.
Here are some functions that split the work into removal, insertion and finally exchanging nodes:
Node* removeNode(Node* &head, int index) {
// If index is out of range, no node is removed, and function returns nullptr
// Otherwise the extracted node is returned.
if (head == nullptr || index < 0) return nullptr;
Node* current = head;
if (index == 0) {
head = head->next;
current->next = nullptr;
return current;
}
while (--index > 0) {
current = current->next;
if (current == nullptr) return nullptr;
}
Node* temp = current->next;
if (temp != nullptr) {
current->next = temp->next;
temp->next = nullptr;
}
return temp;
}
void insertNode(Node* &head, Node* node, int index) {
// If index is too large, node is inserted at the end of the list
// If index is negative, node is inserted at the head of the list
if (index <= 0 || head == nullptr) {
node->next = head;
head = node;
return;
}
Node* current = head;
while (--index > 0 && current->next != nullptr) {
current = current->next;
}
node->next = current->next;
current->next = node;
}
bool exchangeNodes(Node* &head, int indexOne, int indexTwo)
{
// Returns true when successful, false when at least one index
// was out of range, or the two indexes were the same
if (head == NULL || head->next == NULL || indexOne == indexTwo || indexOne < 0) return false;
// To ensure the right order of operations, require the first index is the lesser:
if (indexOne > indexTwo) return exchangeNodes(head, indexTwo, indexOne);
Node* two = removeNode(head, indexTwo);
if (two == nullptr) return false; // out of range
Node* one = removeNode(head, indexOne);
insertNode(head, two, indexOne);
insertNode(head, one, indexTwo);
return true;
}

C++ merging linked list issue

So I'm a beginner to C++ and I have a school project to create a linked list and I'm working on the merge method right now and I'm not sure why it's not working. I identified the problem to be in the second if in the while loop where instead of changing the head_ list node it's changing the list1 list and I don't know why it's doing that
template <typename T>
bool List342<T>::Merge(const List342<T>& list1) {
if (head_ == nullptr) {
head_ = list1.head_;
return true;
}
if (list1.head_ == nullptr) {
return false;
}
Node<T>* l1_ptr = list1.head_;
Node<T>* head_ptr = head_;
while (l1_ptr != nullptr && head_ptr != nullptr) {
if (*head_ptr->data == *l1_ptr->data) {
l1_ptr = l1_ptr->next;
head_ptr = head_ptr->next;
}
else if (*head_ptr->data <= *l1_ptr->data) {
Node<T>* temp = head_ptr->next;
head_ptr->next = l1_ptr;
l1_ptr->next = temp;
l1_ptr = l1_ptr->next;
head_ptr = head_ptr->next;
}
}
return true;
}
I find working with linked lists easier with references and recursion over the list iterators. This version makes sure the second linked list is left in a valid state (though maybe changed), and no new memory is allocated.
template <class T>
bool List342<T>::Merge(List342<T>& list1) {
merge(head_, list1.head_);
}
template <class T>
void merge(List342<T>::Node*& head, List342<T>::Node*& head_o) {
if (head_o == nullptr)
return;
if (head == nullptr) {
head = head_o;
head_o = nullptr;
return;
}
if (*head->data <= *head_o->data) {
merge(head->next, head_o);
} else {
// steal Node from right list1
auto* next = head->next;
auto* next_o = head_o->next;
head->next = head_o;
head_o->next = next;
head_o = next_o; // this works because head_o is a reference
merge(head->next, head_o);
}
}
I think this kind of code makes it much easier to argue about what happens in each case. Let me know if you have questions.

EXC_BAD_ACCESS Error when using linked list

My program still compiles and prints from the inputted data files. However, an error still occurs after everything has printed and so the program doesn't end cleanly.
I get the error specifically in this part of my program
while (current->next != tail)
Basically this program is using a linked list to store information and outputting it into the screen. My particular error is with the clear() function that is supposed to clear the entire linked list with the pop_back() function.
//removes the last object from the linked list – deallocates memory
template <typename T>
void LL<T>::pop_back()
{
if(count==0)
{
//Do nothing. Nothing to remove.
return;
}
else{
Node<T> *current;
current=head;
while (current->next != tail)
{
current=current->next;
}
delete tail;
tail=current;
count--;
}
}
//Clears the linked list
template <typename T>
void LL<T>::clear()
{
Node<T> *current= head;
while (current != NULL)
{
pop_back();
//current=tail;
}
current=tail;
head=tail=NULL;
}
Any help would be much appreciated.
Your pop_back method doesn't handle the case where the tail and the head are the same element (aka a linked list of 1 element). As a quick fix maybe an extra check for that case?
if(count==0)
{
//Do nothing. Nothing to remove.
return;
}
else if (count==1)
{
head = tail = NULL;
count--;
return;
}
Also this loop is infinite as written:
while (current != NULL)
{
pop_back();
//current=tail;
}
maybe while (head != NULL) or while (count != 0)?
You need to update node before the deleted one. Here is simplified version of your pop_back() method:
template <typename T>
void LL<T>::pop_back()
{
Node<T> curr = head;
Node<T> prev = NULL;
while(curr != NULL && curr->next != NULL) // I'm assuming your tail's value is NULL
{
prev = curr;
curr = curr->next;
}
if(curr != NULL)
{
if(prev != NULL)
prev->next = NULL;
delete curr;
--count;
if(count == 0)
head = NULL;
}
}
I didn't compiled the code, but I think idea is clear.
BTW you can improve performance of the clear() method:
Node<T> curr = head;
while(curr != NULL)
{
Node<T> tmp = curr->next;
delete curr;
curr = tmp;
}
head = NULL;
tail = NULL;
count = 0;

C++ delete element function in a doubly linked list

I'm fairly new to C++ and it's data structures. I've made a few functions for my Doubly Linked List Class but i'm having trouble in the delete functions specifically. I've made a deleteHead() function which delete's the first node in the list, a deleteTail() function which deletes the last node in the list and finally a deleteElement(Item) function which goes over the list and deletes the node which has that the Item in it.
Problem is that whenever I try to delete the only remaining node from the list, the program crashes. i.e If I insert a node and then I call the deleteElement function on the same node (and if the node I inserted is the only node in the list) the program crashes.
here's my code.
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T>* current = head;
ListItem<T>* temp;
if (head == NULL) { // if list is empty end the function
return;
}
while (current) {
if (current->value == item) {
if (current == head) { // if item is in the head
deleteHead();
}
else if (current == getTail()) { // if item is in the tail
deleteTail();
}
// if item is between two nodes
else if (current != head && current != getTail()) {
temp = current;
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
current->next = NULL;
current->prev = NULL;
if (current->next == NULL) {
deleteTail();
}
}
}
current = current->next;
}
}
// Delete the Head Node
template <class T>
void LinkedList<T>::deleteHead()
{
if (head != NULL) { // as long as head is not null, delete head
ListItem<T> *current = head;
head = head->next;
current->next = NULL;
head->prev = NULL;
} else {return;} // if head is null, end the function without doing anything
}
// Delete Tail Node
template <class T>
void LinkedList<T>::deleteTail()
{
ListItem<T> *tail = getTail();
tail = tail->prev;
tail->next->prev = NULL;
tail->next = NULL;
}
There are several issues in your code. First of all, you're not checking any pointers before you access them. For example, here:
temp = current;
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
If there's only one element in the list, then its next and prev members will presumably be null. That means trying to assign something to temp->prev->next or temp->next->prev will be an access violation.
The same applies elsewhere, including this line at the end of your while loop:
current = current->next;
At that stage, current could hypothetically have been deleted, meaning trying to access its next member should fail. It probably won't fail at the moment though because of another problem...
Very importantly, you're not actually deleting anything. C++ doesn't have a garbage collector, so you can't just set a raw pointer to null and forget about it. You have to call delete on it to destroy and deallocate the object, otherwise it causes a memory leak. You'll need to fix that throughout your code, and then probably revise all your functions. You need to be very careful not to access an object after it's deleted.
With that said, instead of using raw pointers, you should really use smart pointers (i.e. std::shared_ptr). They take care of deleting the object for you when nothing else has a pointer to it. You still need to avoid accessing a deleted object, but it makes coding simpler, and hopefully more modern/robust.
Suggestions:
Step #1 - Add member variable ListItem<T>* tail to class ListItem<T>.
Step #2 - Replace all calls to getTail() with tail.
Step #3 - In function deleteElement, you can replace:
else if (current != head && current != tail)
with:
else
Step #4 - In function deleteElement, you should replace:
current->next = NULL;
current->prev = NULL;
if (current->next == NULL)
deleteTail();
with:
delete current;
Step #5 - Rewrite function deleteHead as follows:
ListItem<T>* current = head;
if (head == tail)
head = tail = NULL;
else
head = head->next;
delete current;
Step #6 - Rewrite function deleteTail as follows:
ListItem<T>* current = tail;
if (tail == head)
tail = head = NULL;
else
tail = tail->prev;
delete current;
Got the answer right. This was a question in my Data Structures assignment. Here's the code I implemented. Yes, i'm aware it has redundancies and inefficiencies but I had to work within the framework of the assignment.
This is my deleteElement() Function:
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T>* current = head;
ListItem<T>* temp;
if (head == NULL) { // if list is empty end the function
return;
}
while (current) {
if (current->value == item) {
if (current == head) { // if item is in the head
deleteHead();
}
else if (current == getTail()) { // if item is in the tail
deleteTail();
}
else if (current != head && current != getTail()) {
// if item is between two nodes
temp = current;
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
current->next = NULL;
current->prev = NULL;
if (current->next == NULL) {
deleteTail();
}
}
}
current = current->next;
}
}