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
Related
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;
}
As in the title my code gives the said warning and mashes up the memory references.
I was tasked with using nested classes in C++. This code is mostly my code for linked lists from a previous C application but remade for C++.
I ve searched on the internet about said NULL exception and I can t figure it out.
I ll post the code and hope someone can give me some tips.
In the various links and tips on the internet it says that the pointer I am pointing to is referencing to a NULLptr, and that it can t accces a NULL address.
Tried to review it in various forms but it doesn t work.
Header
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <math.h>
using namespace std;
class List
{
private:
class Node {
public:
int data;
Node* next;
Node() {
this->data = NULL;
this->next = NULL;
}
};
Node* head;
public:
List();
void insertList(int data);
void deleteFromList(int data);
void deleteLowerThan(int lower);
void calculateArithmetic();
void showList();
};
#endif
Cpp file
List::List() {
this->head = NULL;
}
void List::insertList(int n) {
Node* new_node = new Node();
new_node->data = n;
new_node->next = head;
head = new_node;
}
void List::deleteFromList(int n) {
Node* temp = head;
Node* prev = NULL;
if (temp != NULL && temp->data == n) {
head = temp->next;
return;
}
while (temp->data != n && temp != NULL) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
}
void List::deleteLowerThan(int n) {
Node* temp = head;
while (temp != NULL) {
if (temp->data < n) {
deleteFromList(temp->data);
}
else {
temp = temp->next;
}
}
}
void List::showList()
{
Node* temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
}
Driver
int main() {
List lista;
lista.insertList(2);
lista.insertList(4);
lista.insertList(6);
lista.insertList(8);
lista.insertList(3);
lista.insertList(1);
lista.insertList(-4);
lista.showList();
lista.deleteFromList(4);
lista.showList();
lista.deleteFromList(8);
lista.showList();
lista.deleteFromList(6);
lista.showList();
lista.deleteLowerThan(3);
lista.showList();
return 0;
}
The problem lies in your deleteFromList function, with this code:
while (temp->data != n && temp != NULL) {
//...
Here, you are trying to check the value of temp->data before you have verified whether or not temp is NULL. Thus, you will, at some point (when you're at the end of the list, and temp is NULL be dereferencing a null pointer - which ain't good!
Instead, just invert the order of the comparisons:
while (temp != NULL && temp->data != n) {
//...
This way, as soon as temp is NULL, the comparison's result will be fully known (see short circuiting), temp->data will not be evaluated, and the loop will stop running.
As pointed out by Adrian and Andy, this line causes temp to be dereferenced before you check if it's NULL:
while (temp->data != n && temp != NULL)
so, just check that it's not NULL first, then dereference it.
Other mentionable problems are the memory leaks. You should have exactly one delete for each new (unless you surrender the pointer to a smart pointer that will do delete for you).
void List::deleteFromList(int n) {
Node* temp = head;
Node* prev = head; // set this if you need to delete head
if(temp != nullptr && temp->data == n) {
head = prev->next;
delete prev; // you forgot this
return;
}
while(temp != nullptr && temp->data != n) {
prev = temp;
temp = temp->next;
}
if(temp == nullptr) return;
prev->next = temp->next;
delete temp; // you forgot this
}
You also need to implement a destructor in List to delete all the nodes in the List when it is destroyed.
A trickier bug is in your deleteLowerThan() function. You iterate over the nodes in your list and call deleteFromList() which will delete the very node you are currently on. In the next iteration, you use the same node pointer in if (temp->data < n) { causing undefined behaviour. In my case, the program seemed to just hang forever.
One possible fix:
void List::deleteLowerThan(int n) {
Node* temp = head;
int tmpdata;
while(temp != nullptr) {
tmpdata = temp->data; // save the nodes data
temp = temp->next; // step before you delete
if(tmpdata < n) {
deleteFromList(tmpdata);
}
}
}
I am trying to insert a node at a both given index in a linked list and just at the end, but I don't understand the syntax or even conceptually what I am doing.
I have an insertTail function and an insertAfter function for both of these problems, but I'm not sure I am implementing them correctly.
void insertTail(T value) {
if (head == NULL) {
insertHead(value);
}
else {
T tailNode = Node(value);
Node* tempPtr = head;
while (tempPtr != NULL) {
tempPtr = tempPtr->next;
}
next = tailNode->data;
}
};
void insertAfter(T value, T insertionNode) {
Node* tempPtr = head;
while (tempPtr->data != insertionNode) {
tempPtr = tempPtr->next;
}
Node* afterNode = new Node(value);
afterNode->next = tempPtr->next;
tempPtr->next = afterNode;
};
My code won't even compile with what I have currently. It gives an error for the first line in the else statement in the insertTail function that reads
'initializing': cannot convert from 'LinkedList<std::string>::Node' to 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>'
Both of your functions are implemented all wrong. They need to look more like this instead (assuming a single-linked list is being used):
void insertTail(T value) {
if (!head) {
insertHead(value);
}
else {
Node* tailNode = head;
while (tailNode->next) {
tailNode = tailNode->next;
}
tailNode->next = new Node(value);
}
}
void insertAfter(T value, Node *insertionNode) {
if (!insertionNode) {
insertTail(value);
}
else {
Node* newNode = new Node(value);
newNode->next = insertionNode->next;
insertionNode->next = newNode;
}
}
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.
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;