I am trying to create an appendToTail function which will add a node to the end of a singly linked list.
I am having trouble in adding a node if the head is NULL(the linked list is empty)
class Node {
private:
Node* next;
int data;
public:
Node(int d, Node* n = NULL)
: data(d)
, next(n)
{
}
void appendToTail(int);
//other trivial functions(getters and setters etc. ) defined and
//declared
};
void Node::appendToTail(int d)
{
Node* end = new Node(d);
Node* n = this;
if (n == NULL)
n = end;
else {
while (n->next != NULL)
n = n->next;
n->next = end;
n->next->next = NULL;
}
end = NULL;
delete end;
}
int main()
{
Node* n = NULL;
n->appendToTail(5);
std::cout << n->getData(); //getData() is a function which
//retrieves the Data member variable
}
I am expecting to get 5 but I am getting an error which appears to be caused because my node remains null.
Now with modern C++ idioms we use smart pointers instead of raw pointers, it gives you the benefit of RAII (Resource acquisition is initialization) mechanism. In addition if you want an elegant solution to your problem you should introduce a List class with which you can express more clearly the concept of an empty list. It would give something like this:
#include <memory>
#include <iostream>
class List
{
public:
class Node
{
private:
std::shared_ptr<Node> next;
int data;
public:
Node(int d):next(nullptr),data(d){}
inline int getData() const {return data;}
inline std::shared_ptr<Node> getNext() const {return next;}
friend List;
};
List():head(nullptr),tail(nullptr){}
void appendToTail(int );
inline std::shared_ptr<Node> getHead() const {return head;}
inline std::shared_ptr<Node> getTail() const {return tail;}
private:
std::shared_ptr<Node> head;
std::shared_ptr<Node> tail;
};
void List::appendToTail(int d)
{
auto newTail = std::make_shared<Node>(d);
if (head == nullptr)
{
head = tail = newTail;
}
else
{
tail->next = newTail;
tail = newTail;
}
}
int main()
{
List l;
l.appendToTail(5);
std::cout<<l.getHead()->getData();
}
But you should definitely prefer std::list<T> or std::vector<T>.
Unfortunately there several errors with your approach. Semantic errors and a logical error with your interpretation of a linked list. Let's start with your initial misunderstanding. You cannot add a new tail to an empty list. Because it is emtpy. Meaning, not yet existing. Only if some object is existing/instantiated you can add a tail. You cannot add something to not existing stuff. So your idea to start with a Node* n = nullptr cannot work logically.
Additionally you are dereferencing a nullptr (major bug). That is also the main problem of your code. Nothing works. You need an instantiated object, before you can call it's member functions.
So before you can populate the list, you need to create/instantiate it initially. So you need to explicitly create the first node in your main function with
Node* n = new Node (5)
Then the list is existing and from now on you can add new members with calling appendToTail.
There are more semantic errors in your code which have luckily no side effects.
You must not delete the 'end' variable in your function. You want to keep the newly allocated memory for the new tail. But you introduced an additional sematic error by setting 'end' to nullptr and then call delete. Deleting a nullptr is a noOp and will do nothing. So, although you have a semantic error, this will not cause any trouble.
There is more:
For a pointer to Null you should always use nullptr.
And, your
if (n == NULL)
is always false. Before that, you assigned this to n. This is never NULL. You can delete the if else. Keep the statements from the else, except the
n->next->next = NULL;
That's not necessary. The constructor did that already for you. As explained, the next 2 statements should also be elimanted.
Additionally you may want to read a little more on the concept of linked lists.
I hope I could help a little
Related
Today I was taught Linked list in class and I wanted to implement it on my own.
Here's the part of the code that I wrote. Note that traverseLL traverses the Linked list and insertAtEnd inserts a new node at the end of the linked list.
I believe I can implement Linked list logic / methods / functions on my own. But my question is, inside insertAtEnd function when I create a newNode with the parameters - my data to be inserted, and nullptr (because inserting at the end), It inserts garbage values (or memory addresses maybe) in my node, ignoring the data passed to the constructor.
using namespace std;
#define NL '\n'
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
data = data;
next = nextPtr;
}
};
void insertAtEnd(Node* &head, int data) {
Node* newNode = new Node(data, nullptr); // <---- Issue in this line
// When I do as above, my linkedlist nodes always store garbage values and not the data being passed.
// However, when I un-comment the below line, I get the correct output.
// newNode->data = data;
if (head == nullptr)
head = newNode;
else {
Node* temp = head;
while (temp->next != nullptr)
temp = temp->next;
temp->next = newNode;
}
}
void traverseLL(Node* head) {
if (head == nullptr)
return;
while (head->next) {
cout << head->data << " -> ";
head = head->next;
}
cout << head->data << NL;
}
int main() {
Node* head = nullptr;
insertAtEnd(head, 10);
insertAtEnd(head, 20);
insertAtEnd(head, 30);
traverseLL(head);
return 0;
}
For example, the output for the above code when keeping newNode->data = data line commented, is :
16259544 -> 16258392 -> 16258392
But when I un-comment that line, my output becomes, which is intended:
10 -> 20 -> 30
Why is this happening? Even though I've defined my constructor, why is it not working?
I think the cause for this is the statement data = data in the constructor.
Reason for this:
Before executing the first statement of constructor, the member variables of the class are allocated memory and contain junk/default values, and when the statement data = data is seen the compiler changes the parameter but not the member variable.
As a result, you are seeing junk/garbage values.
To resolve this we can either explicitly specify the member using this or use member initialization syntax.
You can use any of the following workarounds.
Workarounds:
You can change your class constructor code like any of the below formats:
1.
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
this->data = data; // we are explicitly specifying which data to use
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
Node (int d, Node* nextPtr=nullptr) {
data = d; // as the member variable and local variable are of different names, no conflict
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
// use the member initialization syntax
// Here we are initializing the data while allocating memory itself,
// so answer is perfectly right!
Node (int d, Node* nextPtr=nullptr) : data(data), next(nextPtr) {}
};
More on the member initialization and constructor:
https://en.cppreference.com/w/cpp/language/constructor
How do C++ class members get initialized if I don't do it explicitly?
Hope this helps,
Thanks.
I want to implement a circularly double linked list. this list just includes these chars in a passed in string object
Here is my code, but I always get seg fault. i use a dummy head for this list
#ifndef MY_LIST_H
#define MY_LIST_H
#include <string>
#include <iostream>
using namespace std;
/**------ -----------------
* dummy |->|pred|value|next|
* ------ -----------------
* */
struct Node
{
char value;
Node *next;
Node *pred;
Node( char value): value(value), next(0), pred(0){};
};
class MyList
{
private:
Node* head;
unsigned int count; // count number of node
public:
// default constructor
MyList(): count(0)
{
head = new Node('P');
}
//Constructs a list from a passed-in string object,
MyList(const string& str): count(0)
{
Node *cur = head;
if(count == 0)
{
head-> pred = head;
head-> next = head;
}
else
{
for( unsigned i =0; i< str.length(); ++i)
{
cur->next = new Node(str.at(i));
Node *temp = cur->next;
temp-> pred = cur;
++count;
if(count == str.length())
{
cur->next->next = head;
head-> pred = cur-> next->pred;
}
}
}
}
void print() const
{
Node *cur = head->next;
while( cur != head)
{
cout << cur-> value;
cur = cur-> next;
}
}
};
#endif
You don't seem to understand constructors very well.
Only one constructor is called when you initialize your class. You can call a constructor from another constructor if you want, but that's not by defaut: Can I call a constructor from another constructor (do constructor chaining) in C++?.
In your instance, your second constructor should probably be something like this: MyList(const string& str): MyList() { ... }
That way head wil be properly initalized, and you won't create a segfault.
Additionnally you could run your code in debug mode, in the debugger, and find out the line your code crashes. using namespace ...; in a header is also a bad practice, as you don't know where your header will be included.
It's hard to say exactly what's happening without see how you're using these classes but your MyList constructor overloaded on string is broken right off the bat. It sets count to 0 so you know it will always enter the if clause and never the else.
MyList(const string& str): count(0)
{
Node *cur = head;
if(count == 0)
{
head-> pred = head;
head-> next = head;
}
else . . .
inside the if statement, it tries to dereference head which has never been assigned a value. You do set it in the default constructor but that one also doesn't seem to do anything else.
The purpose of a constructor is to construct a valid object from scratch. Sometimes one constructor overload might delegate to another to avoid repeated code but I'm not sure what you're trying to do here.
Assuming the second constructor was meant to actually be a helper method, well it still doesn't work because count never goes above zero (except in the else clause but you can't get there with count==0).
I'll admit I didn't look very carefully but I'm guessing that if execution this far:
cur->next->next
is not always going to be set when you try to access it. if cur->next is nullptr then your program dies.
I've created class for building a linked list. The class declaration is as follows:
class LinkedList
{
private:
int data;
LinkedList *next;
static int count;
public:
LinkedList(void);
~LinkedList(void);
int insert(int arg);
int remove(int arg);
bool find(int arg);
};
How can I make sure all nodes of this linked list are deleted? The destructor is made responsible for deleting just one node. I used to make linked list like this previously but never thought about clearing the memory.
The naive implementation
~LinkedList() {delete next;}
will do the right thing - delete will call the destructor on the next element, which will delete the one following it, and so on, to delete the whole list.
However, this means that the destructors are called recursively, so that deleting a very long list could cause a stack overflow. Iteration might be better:
~LinkedList() {
while (LinkedList * head = next) {
next = head->next;
head->next = nullptr;
delete head;
}
}
As noted in the comments, it might be more appropriate to have separate List and Node classes, with List responsible for memory management, and Node a simple aggregate containing the data and the link. Then there's less scope for error in the destructor, as it doesn't need to nullify any pointers to prevent recursion:
struct Node {
int data;
Node * next;
};
struct List {
Node * head;
~List() {
while (Node * victim = head) {
head = victim->next;
delete victim;
}
}
};
I am trying to create a function that adds a node to the end of a LinkedList. I know how to do it using loops, but my professor wants it done a certain way and I don't understand why it's not working. He practically gave us all the code for it..
This is the pseudo-code he gave us:
process append(data)
if (not the end)
next->append(data);
else
next=new Node();
next->data=data;
next->data = nullptr;
And this is what I came up with:
struct Node {
int data;
Node* next;
};
struct LinkedList {
Node* head;
LinkedList() {head = nullptr;}
void prepend(int data) {
if (head == nullptr) {
Node* tmp = new Node();
tmp->data=data;
tmp->next=nullptr;
}
else {
Node* tmp = new Node();
tmp->data=data;
tmp->next=head;
head=tmp;
}
}
void append(int data) {
Node* tmp = head;
if (tmp->next != nullptr) {
tmp=tmp->next->append(data);
}
else {
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
}
};
int main()
{
LinkedList LL = LinkedList();
LL.prepend(7);
LL.append(6);
std::cout << LL.head->data << std::endl;
}
My prepend (to add to the beginning of the LinkedList) works fine, but when I try this code, I get
main.cpp:48:20: error: 'struct Node' has no member named 'append'
tmp->next->append(data);
So I'm pretty sure that there's something wrong with saying next->append(data), which from what I understood, is supposed to be recursively calling back the append function until it reaches a nullpointer. I'm thinking maybe there's some sort of way to write it, but people in my class are telling me that the next->append(data) thing SHOULD work, so I guess I'm not exactly sure why this isn't doing anything. I tried instead writing the append function in the Node struct, but then it says that head wasn't declared in the scope and I really just don't know how to work with this. I'm also sort of new to classes/structs in C++ so I'm assuming it's something about that that I'm not understanding.
The class Node has not any method named append so you get that error message:
tmp->next->append(data);
^^^^^^^^^^^^^
struct Node {
int data;
Node* next;
};
To append a node to a linked-list, you don't need an append method within Node. Remove that. Correct the append process in LinkedList::append:
void append(int data) {
Node* tmp = head;
while (tmp->next)
tmp = tmp->next;
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
I did't test, but you need something like above code. At first, it tries to access to the end of list. Then it appends a node.
Recursive implementation:
void append(int data) {
append(data, head);
}
void append(int data, Node *node) {
if (node->next)
append(data, node->next);
else {
tmp->next = new Node();
tmp->next->data = data;
tmp->next->next = nullptr;
}
}
Your append method isn't defined on the Struct Node. Instead it's defined on the LinkedList class so you need to invoke it accordingly. You can redefine the append method to take a node as a parameter or add an append method to the Struct Node itself. Also there's no need to assign the result of append to tmp =
Your append method is void.
tmp->next is a Node, so to call append function, you must declare it in Node struct
Like this
struct Node
{
void append(int data)
{
if (next)
next->append(data);
else
{
next = new Node();
next->data = data;
next->next= nullptr;
}
}
int data;
Node* next;
};
it's clear from the pseudo code next->append(data); that append is meant to be a member of Node.
Here's how you might use Node::append from LinkedList::append
class LinkedList {
void append(int data) {
if (head == nullptr) {
head = new Node();
head->data=data;
head->next=nullptr;
}
else {
head->append(data);
}
}
}
The node structure does not contain any append method.
Moreover, you are splitting work that can be done in one methos to two methods, writing more code.
See my answer to another question here with working code I wrote
https://stackoverflow.com/a/37358192/6341507
As you can see, I solve all in method
AddItem(int i)
I start seeing that creating linked list i kindof har for many people here, so I will further edit my answer there to provide additional information.
Good luck!
I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)