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;
Related
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;
void deletenode(string key) {
if (last == NULL) {
cout << "your circular linked list is an empty one" << endl;
}
else {
node* p = last->next;
node* prev = last;
do {
if (p->title == key) {
node* temp = p;
prev->next = p->next;
delete(temp);
}
else {
p = p->next;
prev = prev->next;
}
} while (p != last->next);
}}
I was trying to delete a node with key value. For instance, if node p->title is my key then I want to delete that node. However, I implemented it with other values but the code doesn't seem to work or delete a node with key value from my circular linked list. What is the mistake in the function?
circular linked list value "cat", "dog", "rat", "horse", the key to be deleted was "dog". When I traverse throughout the linked list after the deletion it still printed everything including "dog", which means deletion didn't work.
Anytime you write a "delete from the linked list" function, you have to account for the possibility that you are deleting from the "head" or whatever pointer you are referencing with the list. The common pattern is for the function to return the new head of the list if it changed, else return the current head.
Node* deletenode(Node* head, const string& key) {
// empty list
if (head == nullptr) {
return nullptr;
}
// single item list
if (head->next == nullptr || head->next == head) {
if (head->title == key) {
delete head;
head = nullptr;
}
return head;
}
// two or more item list, possibly circular
Node* prev = head;
Node* current = head->next;
Node* first = current;
while (current && current->title != key) {
prev = current;
current = current->next;
if (current == first) {
break;
}
}
if (current == nullptr || current->title != key) {
return head; // not found
}
prev->next = current->next;
if (current == head) {
head = current->next;
}
delete current;
return head;
}
I don't see the full code so I can't make a comment I tried to implement the function, hope it helps you with the comments.
void deleteNodeWithKey(node* head, string key)
{
node *curr = head;
node *last , *temp;
//Search for last node
while (curr->next != head)
{
curr = curr->next;
}
last = curr;
//If head is the desired key, make head's next new head
//and connect last node to new head
if (head->key == key)
{
temp = head->next;
delete head;
head = temp;
last->next = head;
return;
}
temp = head->next;
//Search for node with the given key
node *prev = head;
while (temp != head)
{
if (temp->key == key)
{
prev->next = temp->next;
delete temp;
return;
}
temp = temp->next;
prev = prev->next;
}
//If function gets here, key was not found
}
I made some changes to your code
void deletenode(string key) {
if (last == NULL) {
cout << "your circular linked list is an empty one" << endl;
}
else {
node* prev = last;
// If head is to be deleted
if (last->title == key) {
while (prev->next != last)
prev = (prev)->next;
prev->next = last->next;
free(last);
last = prev->next;
return;
}
node* p = last->next;
do {
if (p->next->title == key) {
node* temp = p->next;
p->next = temp->next;
delete(temp);
}
else {
p = p->next;
prev = prev->next;
}
} while (p != last->next);
}
}
I'm curious what's the difference in two functions below:
void Add(T x)
{
if (head == nullptr)
{
head = (new Node<T>());
head->set(x);
head->set_next(nullptr);
return;
}
Node<T> *temp = head;
while (temp->get_next() != nullptr)
{
temp = temp->get_next();
}
temp->set_next(new Node<T>());
(temp->get_next())->set(x);
(temp->get_next())->set_next(nullptr);
}
void Add(T x)
{
Node<T> *temp = head;
while (temp != nullptr)
{
temp = temp->get_next();
}
temp = new Node<T>();
temp->set(x);
temp->set_next(nullptr);
}
First one works properly, second one is making segm fault. Why is that? I thought outcome should be the same, just wanted to make code a little bit shorter but I'm clearly missing something
void RemoveDuplicates(Slist& l)
{
if (l.head == NULL) {
return;
}
Node* cur = l.head;
while (cur != NULL && cur->next != NULL) {
Node* prev = cur;
Node* temp = cur->next;
while (temp != NULL) {
if (temp->data == cur->data) {
prev->next = temp->next;
cur->next = prev->next;
temp = prev->next;
}
else {
prev = prev->next;
temp = temp->next;
}
}
cur = cur->next;
}
}
Hi, I want to remove duplicates from linked list (0 is NULL)
input: 1->2->2->4->2->6->0
outPut: 1->2->4->6->0
Result after I run my program is:
1->2->6
Where am I wrong? Please help me
Here is my solution for your problem:
bool alreadyExist(Node head)
{
Node cur = head;
while(cur.next != nullptr)
{
if(cur.next->data == head.data) {
return true;
}
cur = *cur.next;
}
return false;
}
void RemoveDuplicates(Slist& l)
{
if (l.head == nullptr) {
return;
}
Node* head = l.head;
Node* curPtr = l.head->next;
while(curPtr != nullptr)
{
if(alreadyExist(*curPtr) == false)
{
head->next = curPtr;
head->next->prev = head;
head = head->next;
curPtr = curPtr->next;
}
else
{
Node* backup = curPtr;
curPtr = curPtr->next;
// delete duplicate elements from the heap,
// if the nodes were allocated with new, malloc or something else
// to avoid memory leak. Remove this, if no memory was allocated
delete backup;
}
}
}
Important: The destructor of the Node-object is NOT allowed to delete the linked object behind the next and prev pointer.
It results, for your input-example, in the output 1->4->2->6->0. Its not totally exact the order, you want as output, but each number exist only one time within the output. It only add the last time of a duplicate number.
I don't really know, if you use C or C++, but because I prefer C++, I replaced the NULL with nullptr in the code. The delete can be removed, if the objects are not on the HEAP create with malloc or new.
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;
}
}