I have written the following link list append, prepend and print methods for LinkedList:
class Node {
public:
int data;
Node *next;
Node(int data) {
this->data = data;
}
};
class LinkedList {
private:
Node *header;
Node *tail;
int size;
public:
LinkedList() {
header = NULL;
tail = NULL;
size = 0;
}
int getSize() {
return size;
}
void append(int data) {
Node *n = new Node(data);
if (header == NULL) {
header = n;
tail = n;
}
else {
tail->next = n;
tail = n;
}
size++;
}
void prepend(int data) {
Node *n = new Node(data);
if (header == NULL) {
header = n;
tail = n;
}
else {
Node *temp = header;
header = n;
n->next = temp;
}
size++;
}
void toString() {
Node *temp = header;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
};
int main()
{
LinkedList list;
list.append(1);
list.append(2);
list.append(3);
list.toString();
return 0;
}
But the program is giving bad access after reaching the last node while printing the list. What is the problem with this code? Can anyone please explain on this?
append() is not initializing the n->next member to NULL. You should do that initialization in Node's constructor, eg:
class Node {
public:
int data;
Node *next;
Node(int data) {
this->data = data;
this->next = NULL; // <-- add this!
}
};
Alternatively:
class Node {
public:
int data;
Node *next = nullptr;
Node(int data) : data(data) {}
};
Or:
class Node {
public:
int data;
Node *next;
Node(int data, Node *next = nullptr) : data(data), next(next) {}
};
That being said, your LinkedList is leaking nodes. You need to add a destructor to free the nodes. You should also add a copy constructor and a copy assignment operator, per the Rule of 3. And in C++11 and later, add a move constructor and a move assignment operator, per the Rule of 5.
Try this:
class Node {
public:
int data;
Node *next;
Node(int data, Node *next = nullptr) : data(data), next(next) {}
};
class LinkedList {
private:
Node *header = nullptr;
Node *tail = nullptr;
int size = 0;
public:
LinkedList() = default;
LinkedList(const LinkedList &src) : LinkedList() {
Node *temp = src.header;
while (temp) {
append(temp->data);
temp = temp->next;
}
}
LinkedList(LinkedList &&src) : LinkedList() {
std::swap(header, src.header);
std::swap(tail, src.tail);
std::swap(size, src.size);
}
~LinkedList() {
Node *temp = header;
while (temp) {
Node *n = temp->next;
delete temp;
temp = n;
}
}
LinkedList& operator=(LinkedList src) {
std::swap(header, src.header);
std::swap(tail, src.tail);
std::swap(size, src.size);
return *this;
}
int getSize() const {
return size;
}
void append(int data) {
Node **temp = (tail) ? &(tail->next) : &header;
*temp = new Node(data);
tail = *temp;
++size;
}
void prepend(int data) {
header = new Node(data, header);
if (!tail) tail = header;
++size;
}
void toString() const {
Node *temp = header;
while (temp) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
};
int main()
{
LinkedList list;
list.append(1);
list.append(2);
list.append(3);
list.toString();
return 0;
}
You should always initialize the members of your class.
Node(int data)
: data(data)
, next(nullptr)
{
}
You've forgotten to assign n->next in append(). I suggest that you add an argument to your Node constructor to not forget that:
class Node {
public:
int data;
Node *next;
// make the constructor initialize both "data" and "next"
Node(int data, Node* next) :
data(data),
next(next)
{}
};
With that, your append() and prepend() functions would have to supply the next node upon construction, making mistakes like this a little harder:
void append(int data) {
Node *n = new Node(data, nullptr);
if (header == nullptr) header = n;
else tail->next = n;
tail = n;
++size;
}
void prepend(int data) {
Node *n = new Node(data, header);
if (header == nullptr) tail = n;
header = n;
++size;
}
You also need to add a destructor to delete all the nodes to not leak memory.
Related
ok, I created a linked list using the Node class and List class. But whenever I run it using the List object, it throws an exception when I return the head in the getHead() function in Node.cpp
these are the files that I created please if anyone could know why this exception is coming it would be a blessing
//**NODE.h**
#include<iostream>
using namespace std;
class Node{
private:
Node* head;
int data;
public:
Node();
Node(int); //insert data
void setHead(Node*);
Node* getHead();
void setData(int);
int getData();
void printData(Node*);
};
//**Node.cpp**
#include"Node.h"
Node::Node(){
//Node* head = new Node();
head = NULL;
data = 0;
}
Node::Node(int DATA){
//Node* head = new Node();
head = nullptr;
data = DATA;
}
int Node::getData(){ //DATA SETTER
return this->data;
}
void Node::setData(int DATA){ //DATA GETTER
this->data = DATA;
}
Node* Node::getHead(){
return head;
}
void Node::setHead(Node* NextAddress){
this->head = NextAddress;
}
void Node::printData(Node* node){
while(node != nullptr){
cout<< this->data <<"\n";
node = node->head;
}
}
//**List.h**
#include"Node.h"
class List : public Node{
private:
Node* head;
Node* current;
Node* prevcurrent;
public:
List();
//void setList(int);
void insertAtBack(Node* , int);
void insertAtFront(Node* , int);
bool search(int);
void print();
~List();
};
//**List.cpp**
#include"List.h"
List::List(){
head=nullptr;
current=nullptr;
prevcurrent=nullptr;
}
void List::insertAtBack(Node* head , int Data){
Node* newNode = new Node();
newNode->setData(Data);
newNode->setHead(head); //sets the address of the next node into the newly added node
head = newNode;
}
void List::insertAtFront(Node* head, int Data) {
Node* temp = new Node();
}
bool List::search(int num){
Node* temp = head;
while (temp->getHead()!=nullptr)
{
if (temp->getData() == num)
{
return true;
}
temp->setHead(temp->getHead()); //itereates the adress in the emp node to store the address of the next node fro the while loop
}
}
void List::print(){
Node* temp=head;
while (temp->getHead() != nullptr)
{
cout<<temp->getData()<<" ";
}
}
List::~List() {
Node* temp = head;
while (temp->getHead() != nullptr)
{
Node* temp2 = temp;
temp = temp->getHead();
delete temp2;
}
}
//**main.cpp**
#include"List.h"
int main(){
// cout<<"running\n";
// Node box(5); this works
// cout<<box.getData();
List obj;
Node node; //this will throw an exception
obj.insertAtBack(&node,5);
obj.print();
}
Exception is thrown due to print:
void List::print() {
Node *temp = head;
while (temp->getHead() != nullptr) {
cout << temp->getData() << " ";
}
}
Here, a check is missing if temp (or equally head) is a nullptr before you dereference it in temp->getHead()
Same on List::~List
I am currently learning Linked Lists and have implemented a singly linked list with Append and Prepend methods where I have allocated objects of type Node on heap using the 'new' operator. Do I need to deallocate the object on heap using 'delete', and if so then how do I do it ?
Here is my code:-
class List
{
private:
class Node
{
public:
int data;
Node* next;
Node()
{
data = 0;
next = NULL;
}
Node(const int& data)
{
this->data = data;
}
};
Node* head;
public:
List()
{
head = NULL;
}
void Append(const int&val);
void Prepend(const int&val);
void DisplayAll();
};
void List::Append(const int&val)
{
Node* n = new Node(val); //dynamically allocated
if (head == NULL)
{
head = n;
return;
}
Node* temp = NULL;
temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = n;
}
void List::Prepend(const int&val)
{
Node* node = new Node(val);//dynamically allocated
if (head == NULL)
{
head = node;
return;
}
node->next = head;
head = node;
}
void List::DisplayAll()
{
Node* temp = head;
while (temp != NULL)
{
std::cout << temp->data << ' ';
temp = temp->next;
}
}
For starters this constructor
Node(const int& data)
{
this->data = data;
}
does not initialize the data member next. As a result member functions Append and Prepend have a bug
void List::Append(const int&val)
{
Node* n = new Node(val); //dynamically allocated
if (head == NULL)
{
head = n;
return;
}
//...
and
void List::Prepend(const int&val)
{
Node* node = new Node(val);//dynamically allocated
if (head == NULL)
{
head = node;
return;
}
//...
The data member next of the head node has an indeterminate value.
You could declare the class Node simpler like
struct Node
{
int data;
Node* next;
};
Node* head = nullptr;
In this case for example the function Prepend will look like
void List::Prepend( const int &val )
{
head = new Node { val, head };
}
And the constructor will look like
List() = default;
To free all allocated nodes in the list you could write two more member functions clear and the destructor that calls the function clear.
For example
#include <functional>
//...
class List
{
//...
public:
void clear()
{
while ( head ) delete std::exchange( head, head->next );
}
~List() { clear(); }
//...
Also you should at least either write a copy constructor and the copy assignment operator or define them as deleted.
I'm writing my own linked list class (for educational purposes) and here it is:
My code
#include <iostream>
using namespace std;
#define PRINT(x) #x << " = " << x << " "
struct ListNode {
int val;
ListNode* next = nullptr;
ListNode(int x) : val(x), next(nullptr) {}
};
class LinkedList {
private:
ListNode* _head;
unsigned long long int _size;
public:
LinkedList() :_head(nullptr), _size(0) {}
LinkedList(ListNode* _h) :_head(_h), _size(0) {
ListNode* node = _head;
while (node != nullptr) {
_size++;
node = node->next;
}
}
// Copy constructor
LinkedList(const LinkedList& obj) {
ListNode* node = obj._head;
while (node != nullptr) {
this->add(node->val);
node = node->next;
}
}
~LinkedList() {
while (_head != nullptr) {
remove();
}
}
void add(const int& value) {
ListNode* node = new ListNode(value);
node->next = _head;
_head = node;
_size++;
}
int remove() {
int v = _head->val;
ListNode* node = _head;
_head = _head->next;
delete node;
_size--;
return v;
}
void print() {
if (size() == 0) {
cout << "List is empty" << endl;
return;
}
ListNode* node = _head;
while (node->next != nullptr) {
cout << node->val << " -> ";
node = node->next;
}
cout << node->val << endl;
}
unsigned long long int size() { return _size; }
ListNode* head() { return _head; }
};
int main() {
LinkedList L;
L.add(4);
L.add(3);
L.add(2);
L.add(1);
L.print();
LinkedList L2(L);
return 0;
}
The problem is that when I run this code, I get this error: error for object 0x7fff5b8beb80: pointer being freed was not allocated I don't understand why. My logic beyond the copy constructor is simple: I iterate over the list I'm copying, which is obj, and I add a new element to this list, which is the list I'm copying to. Since my add() function creates a new element with, well, new, I can't see where my two lists share an element which I'm trying to delete twice in the destructor. What am I doing wrong?
You forgot to initialize your _head in copy constructor:
// Copy constructor
LinkedList(const LinkedList &obj) {
_head = NULL; // <- Add This
ListNode *node = obj._head;
while (node != nullptr) {
this -> add(node -> val);
node = node -> next;
}
}
I implemented my own simple version of a doubly linked list. Unfortunately, there seems to be an error with it. The head of the list seems to move to the new Node, each time I add one with push_back. Because of this, print will print the last value indefinitely.
Linked List:
struct doubly_linked_list
{
Node *head = nullptr;
Node *tail = nullptr;
void push_back(Node n)
{
if (this->head == nullptr)
{
this->head = &n;
this->tail = nullptr;
}
n.prev = this->tail;
if (this->tail)
{
n.prev->next = &n;
}
this->tail = &n;
}
void print()
{
Node *tmp = this->head;
while (tmp != nullptr)
{
std::cout << tmp->data << ", ";
tmp = tmp->next;
}
}
};
Where Node is implemented as
struct Node
{
int data;
Node *next = nullptr;
Node *prev = nullptr;
Node(int data)
{
this->data = data;
}
Node()
{
this->data = -1;
}
};
main
int main()
{
doubly_linked_list dl;
dl.push_back(Node{3});
dl.push_back(Node{2});
dl.push_back(Node{1});
dl.push_back(Node{0});
dl.push_back(Node{5});
dl.print(); // print 5 forever
}
Disclaimer: Pls be aware that the topic of this post is educational. I know about the lists in the c++ standard.
Here is a working example with raw pointers, deppending on what you are doing you might want to change that to smart pointers.
#include <iostream>
struct Node
{
int data;
Node *next = nullptr;
Node *prev = nullptr;
Node(int data)
{
this->data = data;
}
Node()
{
this->data = -1;
}
};
struct doubly_linked_list
{
Node *head = nullptr;
Node *tail = nullptr;
void push_back(Node* n)
{
if (this->head == nullptr)
{
this->head = n;
this->tail = nullptr;
}
n->prev = this->tail;
if (this->tail)
{
n->prev->next = n;
}
this->tail = n;
}
void print()
{
Node *tmp = this->head;
while (tmp != nullptr)
{
std::cout << tmp->data << ", ";
tmp = tmp->next;
}
}
};
int main()
{
doubly_linked_list dl;
dl.push_back(new Node{3});
dl.push_back(new Node{2});
dl.push_back(new Node{1});
dl.push_back(new Node{0});
dl.push_back(new Node{5});
dl.print(); // print 5 forever
}
I decided to practice my linked-list knowledge, and decided to create one in C++!
I ran this code on two different online compilers - one worked, and the other is giving me a segfault. I cannot figure out what the problem is within my code, and am wondering if you can help me.
#include <iostream>
using namespace std;
struct Node {
int val;
Node *next;
Node(int val){
this->val = val;
this->next = NULL;
}
};
class LinkedList {
public:
Node *head;
void insertAtHead(Node *temp)
{
if (head == NULL)
{
head = temp;
}
else
{
temp->next = head;
head = temp;
}
}
void printList()
{
Node *temp = head;
while (temp != NULL)
{
cout << temp->val << endl;
temp = temp->next;
}
}
void insertAtBack(Node *temp)
{
if (head == NULL)
{
head = temp;
return;
}
Node *current = head;
while (current->next != NULL){
current = current->next;
}
current->next = temp;
}
void deleteNode(Node *temp)
{
if (head == NULL)
{
cout << "Empty List";
return;
}
if (head->val == temp->val)
{
head = head->next;
return;
}
Node *current = head;
while (current->next != NULL)
{
if (current->next->val == temp->val)
{
current->next = current->next->next;
return;
}
current = current->next;
}
}
};
int main()
{
Node *temp = new Node(10);
Node *temp2 = new Node(4);
Node *temp3 = new Node(17);
Node *temp4 = new Node(22);
Node *temp5 = new Node(1);
LinkedList x;
x.insertAtHead(temp);
x.insertAtHead(temp2);
x.insertAtBack(temp3);
// x.insertAtBack(temp4);
// x.insertAtBack(temp5);
// x.deleteNode(temp);
x.printList();
return 0;
}
The problem I am encountering is when I use the insertAtBack() method. It gives me a segfault, but I do not see what's wrong with the logic. It is pretty straight forward. The insertAtFront() method works, but once I call insertAtBack() my code fails.
make sure to initialize Node *head to NULL.
After insert temp(which is value 10), temp->next value becomes undefined value, because Node *head is undefined value.
Your LinkedList class is not initializing its head member. You need to add a constructor to initialize head to NULL.
Also, the class is leaking memory, as there is no destructor to free the nodes when a LinkedList instance is destroyed, and deleteNode() doesn't free the node being removed, either.
Try something more like this:
#include <iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int val) : val(val), next(NULL) { }
};
class LinkedList
{
private:
Node *head;
// if you are NOT using C++11 or later, add these
// until you are reading to tackle copy semantics!
/*
LinkedList(const LinkedList &);
LinkedList& operator=(const LinkedList &);
*/
public:
LinkedList() : head(NULL) {} // <-- add this!
~LinkedList() // <-- add this!
{
Node *current = head;
while (current)
{
Node *next = current->next;
delete current;
current = next;
}
}
void insertAtHead(Node *temp)
{
if (!head)
{
head = temp;
}
else
{
temp->next = head;
head = temp;
}
}
void printList()
{
Node *current = head;
while (current)
{
cout << current->val << endl;
current = current->next;
}
}
void insertAtBack(Node *temp)
{
if (!head)
{
head = temp;
return;
}
Node *current = head;
while (current->next) {
current = current->next;
}
current->next = temp;
}
void deleteNode(Node *temp)
{
if (!head)
{
cout << "Empty List";
return;
}
if (head == temp)
{
head = temp->next;
delete temp;
return;
}
Node *current = head;
while (current->next)
{
if (current->next == temp)
{
current->next = temp->next;
delete temp;
return;
}
current = current->next;
}
}
// if you ARE using C++11 or later, add these until
// you are reading to tackle copy and move semantics!
/*
LinkedList(const LinkedList &) = delete;
LinkedList(LinkedList &&) = delete;
LinkedList& operator=(const LinkedList &) = delete;
LinkedList& operator=(LinkedList &&) = delete;
*/
};
int main()
{
Node *temp = new Node(10);
Node *temp2 = new Node(4);
Node *temp3 = new Node(17);
Node *temp4 = new Node(22);
Node *temp5 = new Node(1);
LinkedList x;
x.insertAtHead(temp);
x.insertAtHead(temp2);
x.insertAtBack(temp3);
// x.insertAtBack(temp4);
// x.insertAtBack(temp5);
// x.deleteNode(temp);
x.printList();
return 0;
}
Which can then be simplified further:
#include <iostream>
using namespace std;
struct Node
{
int val;
Node *next;
Node(int val, Node *next = NULL) : val(val), next(next) { }
};
class LinkedList
{
private:
Node *head;
// if you are NOT using C++11 or later, add these
// until you are reading to tackle copy semantics!
/*
LinkedList(const LinkedList &);
LinkedList& operator=(const LinkedList &);
*/
public:
LinkedList() : head(NULL) {} // <-- add this!
~LinkedList() // <-- add this!
{
Node *current = head;
while (current)
{
Node *next = current->next;
delete current;
current = next;
}
}
Node* insertAtHead(int value)
{
Node *temp = new Node(value, head);
if (!head)
head = temp;
return temp;
}
void printList()
{
Node *current = head;
while (current)
{
cout << current->val << endl;
current = current->next;
}
}
Node* insertAtBack(int value)
{
Node **current = &head;
while (*current)
current = &((*current)->next);
*current = new Node(value);
return *current;
}
/*
void deleteNode(Node *temp)
{
Node *current = head, *previous = NULL;
while (current)
{
if (current == temp)
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
delete temp;
return true;
}
previous = current;
current = current->next;
}
cout << "Not found" << endl;
return false;
}
*/
bool deleteValue(int value)
{
Node *current = head, *previous = NULL;
while (current)
{
if (current->val == value)
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
delete temp;
return true;
}
previous = current;
current = current->next;
}
cout << "Not found" << endl;
return false;
}
// if you ARE using C++11 or later, add these until
// you are reading to tackle copy and move semantics!
/*
LinkedList(const LinkedList &) = delete;
LinkedList(LinkedList &&) = delete;
LinkedList& operator=(const LinkedList &) = delete;
LinkedList& operator=(LinkedList &&) = delete;
*/
};
int main()
{
LinkedList x;
x.insertAtHead(10);
x.insertAtHead(4);
x.insertAtBack(17);
// x.insertAtBack(22);
// x.insertAtBack(1);
// x.deleteValue(10);
x.printList();
return 0;
}