NOTE: This question is not about reversing a linked list using recursion but about why it crashes. It's more about dynamic memory really.
I'm implementing a linked list and want to have a function in it that recursively reverses it.
struct sNode {
int data;
sNode* next;
sNode(int x) {
data = x;
next = 0;
}
sNode(int x, sNode* n) {
data = x;
next = n;
}
};
class SLL {
public:
SLL() : head(0) {}
sNode* getHead() { return head;}
void reverseRec(sNode*); // Reverse the list using recursion;
private:
sNode* head;
};
void SLL::reverseRec(sNode* node) {
// Reverse the list using recursion
if (node == 0) {
head = node;
return;
}
reverseRec(node->next);
sNode* temp = node->next;
temp->next = node;
node->next = 0;
}
int main() {
SLL l1;
l1.addAtEnd(1);
l1.addAtBeg(2);
l1.addAtPos(3, 2);
l1.reverseRec(l1.getHead());
return 0;
}
The program just crashes. Please help me figure out the reason. I think it's got to do with the arguments of the function.
This is a problem.
if (node == 0) {
head = node;
return;
}
You just made the list an empty list. That should be (prefer to use nullptr or NULL instead of 0 for pointers):
if (node == nullptr || node->next == nullptr ) {
head = node;
return;
}
Related
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 implemented a linked list in a class with addToHead, addToTail, deleteFromHead, deleteFromTail, isEmpty, and display functions, and I want to sort the linked list in ascending order in an inherited class, so I made a class TSortedList with two functions; the sortList function that compares the elements of the linked list with each other, and the display() function that display the linked list after sorting it. But when I run the code nothing appear to me, however when I sort it through a function in the parent class, not the inherited class it works, so I do not know where is the problem
#include <iostream>
using namespace std;
class Node {
public:
Node() {
next = 0;
//write your modification here
}
Node(int el, Node *ptr = 0) { //write your modification for the constructor arguments here
info = el;
next = ptr;
}
int info;
Node *next;
//write your modification here
};
class LList {
protected:
Node *head, *tail;
public:
LList() {
head = tail = 0;
}
~LList(){
for (Node *p; !isEmpty(); ) {
p = head->next;
delete head;
head = p;
}
}
int isEmpty() {
return head == 0;
}
virtual void addToHead(int el){
head = new Node(el,head);
if (tail == 0)
tail = head;
}
virtual void addToTail(int el){
if (tail != 0) { // if list not empty;
tail->next = new Node(el);
}
else head = tail = new Node(el);
}
int deleteFromHead(){ // delete the head and return its info;
int el = head->info;
Node *tmp = head;
if (head == tail) // if only one node in the list;
head = tail = 0;
else head = head->next;
delete tmp;
return el;
}
int deleteFromTail(){ // delete the tail and return its info;
int el = tail->info;
if (head == tail) { // if only one node in the list;
delete head;
head = tail = 0;
}
else { // if more than one node in the list,
Node *tmp; // find the predecessor of tail;
for (tmp = head; tmp->next != tail; tmp = tmp->next);
delete tail;
tail = tmp; // the predecessor of tail becomes tail;
tail->next = 0;
}
return el;
}
bool isInList(int el) const{
Node *tmp;
for (tmp = head; tmp != 0 && !(tmp->info == el); tmp = tmp->next);
return tmp != 0;
}
virtual void displayList(){
if (head == 0) // if empty list;
return;
Node *tmp = head;
for (tmp = head; tmp != 0; tmp = tmp->next){
cout<<tmp->info<<endl;
}
}
};
class TSortedList: public LList, public Node
{
protected:
Node *current = head, *index = 0;
int temp;
public:
void sortList() {
if(head == 0) {
return;
}
else {
while(current != 0) {
//Node index will point to node next to current
index = current->next;
while(index != 0) {
//If current node's data is greater than index's node data, swap the data betweenthem
if(current->info > index->info) {
temp = current->info;
current->info = index->info;
index->info = temp;
}
index = index->next;
}
current = current->next;
}
}
}
void display() {
//Node current will point to head
Node *current = head;
if(head == 0) {
return;
}
while(current != 0) {
//Prints each node by incrementing pointer
cout<<current->info<<endl;
current = current->next;
}
cout<<"\n"<<endl;
}
};
int main()
{
//Adds data to the list
LList myList;
myList.addToHead(1);
myList.addToHead(7);
myList.addToHead(3);
TSortedList sortt;
sortt.sortList();
sortt.display();
return 0;
}
Your TSortedList sortt; is empty; you never add anything to it.
What do you expect it to display?
This should work as you expected:
int main()
{
//Adds data to the list
TSortedList myList;
myList.addToHead(1);
myList.addToHead(7);
myList.addToHead(3);
myList.display(); // this should be in original order
myList.sortList();
myList.display(); // this should be sorted
return 0;
}
Also, why are you deriving your TSortedList from Node?
class TSortedList: public LList, public Node
The removeNode() function implements a circular doubly linked list which has a sentinel node. What I am trying to do is defined in pseudo code next to the function. I simply just am having a hard time understanding how to do so.
#include "CDLList.h"
#include <iostream>
using namespace std;
ListNode *createList()
{
ListNode *sentinel = new ListNode();
sentinel->last = sentinel;
sentinel->next = sentinel;
return sentinel;
}
void destroyList(ListNode *&sentinel)
{
// Delete any item nodes
clearList(sentinel);
// Delete the sentinel node
delete sentinel;
sentinel = nullptr;
}
bool isEmpty(ListNode *sentinel)
{
return (sentinel == sentinel->next);
}
ListNode *findNode(ListNode *sentinel, string value)
{
ListNode *pCurrNode = sentinel->next;
while (pCurrNode != sentinel)
{
// Check if we found the node
if (pCurrNode->item == value)
{
return pCurrNode;
}
// Move to next node
pCurrNode = pCurrNode->next;
}
return nullptr;
}
void addItem(ListNode *sentinel, string value)
{
ListNode *newNode = new ListNode;
newNode->item = value;
newNode->last = sentinel->last;
newNode->next = sentinel;
sentinel->last->next = newNode;
sentinel->last = newNode;
}
void removeNode(ListNode *node) // Implement this function!
{
// Unlink node
// Delete node
}
The removeNode() function is called within these two functions
void removeItem(ListNode *sentinel, string value)
{
ListNode *node = findNode(sentinel, value);
// If the item was not found, there's nothing to do (remove)
if (node == nullptr)
{
return;
}
removeNode(node);
}
void clearList(ListNode *sentinel)
{
while (!isEmpty(sentinel))
{
removeNode(sentinel->next);
}
}
Here's the function implementation:
void removeNode(ListNode *node)
{
if(!isEmpty(node))
{
ListNode* nodeLast = node->last;
ListNode* nodeNext = node->next;
// Unlink node
nodeLast->next = nodeNext;
nodeNext->last = nodeLast;
}
// Delete node
delete node;
}
I need to print out the number of nodes in a linked list. My teacher said that the linked list keeps track of its data and "knows" how many nodes are in it. So, I should not need a while loop to determine the size of the linked list. I have trouble figuring out a way other than a while loop to print out the size.
this is the linked list:
template <class T>
class LinkedList
{
private:
struct ListNode
{
T data ;
struct ListNode * next;
};
ListNode *head;
public:
LinkedList() { head = nullptr; }
~LinkedList();
// Linked list operations
void insertNode(T);
bool deleteNode(T);
void displayList() const;
};
/////////// Implementation portion of linked list with template //////////////
// displayList: print all list data
template <class T>
void LinkedList<T>::displayList() const
{
ListNode * ptr = head;
while (ptr != nullptr)
{
cout << ptr->data << endl;
ptr = ptr->next;
}
}
// insertNode: add a node in list order
template <class T>
void LinkedList<T>::insertNode(T newValue)
{
ListNode *newNode;
ListNode *pCur;
ListNode *pPre = NULL;
newNode = new ListNode;
newNode->data = newValue;
newNode->next = nullptr;
if (head == nullptr)
{
head = newNode;
}
else
{
pCur = head;
pPre = nullptr;
while (pCur != nullptr && pCur->data < newValue)
{
pPre = pCur;
pCur = pCur->next;
}
if (pPre == nullptr)
{
head = newNode;
newNode->next = pCur;
}
else
{
pPre->next = newNode;
newNode->next = pCur;
}
}
}
// deleteNode: delete a node if found
template <class T>
bool LinkedList<T>::deleteNode(T toBeDeleted)
{
ListNode *pCur;
ListNode *pPre;
if (!head)
return true;
pCur = head;
pPre = NULL;
while (pCur != NULL && pCur->data < toBeDeleted)
{
pPre = pCur;
pCur = pCur->next;
}
if (pCur != NULL && pCur->data == toBeDeleted)
{
if (pPre)
pPre->next = pCur->next;
else
head = pCur->next;
delete pCur;
return true;
}
return false;
}
// destructor, delete all nodes
template <class T>
LinkedList<T>::~LinkedList()
{
ListNode *ptr = head;
while (ptr != NULL)
{
head = head->next;
delete ptr;
ptr = head;
}
}
Using the code you've defined, the size of the list is not stored by the list directly. Further to this, the main advantage of linked list is that each node does not know about the rest of the list, and storing the size would defeat the purpose of this.
However, you may have misunderstood what was asked of you in terms of not using a while loop. Each node knows that it's length is 1+(the length of it's tail), and so the more suitable implementation for getting the length of a linked list is recursion, not iteration.
Here is an example of a very simple LinkedList class, that implements the simple methods using recursion. As you can see, the code uses no iteration, only making a check for it's own data, then calling the same method for the next node. Although recursion in procedural languages is less efficient in most cases, for structures like this there is no doubting it is elegant.
#include <iostream>
template<class T>
class LinkedList
{
private:
T data;
LinkedList* next;
public:
LinkedList()
: LinkedList(T()) {
}
LinkedList(T value)
: data(value), next(nullptr) {
}
~LinkedList() {
delete next;
}
void insertNode(T newValue) {
if (!next) {
next = new LinkedList(newValue);
return;
}
next->insertNode(newValue);
}
void displayList() const {
std::cout << data << std::endl;
if (next) {
next->displayList();
}
}
T& at(int N) {
if (N == 0) {
return this->data;
}
return next->at(N-1);
}
int size() {
if (!next) {
return 1;
}
return 1+next->size();
}
};
int main(int argc, char const *argv[])
{
LinkedList<int>* test = new LinkedList<int>(0);
for (int i = 1; i < 10; ++i) {
test->insertNode(i);
}
std::cout << "List of length: " << test->size() << std::endl;
test->displayList();
return 0;
}
You'll notice I haven't included deleteNode, that's because writing it for the oversimplified class above is not possible for the case where the list only has one node. One possible way to implement this is to have a wrapper class, much like you in the original code, that is a pointer to the start of a linked list. See here.
I am trying to make a double linked list. Function push(int x) should add a node to the list and make the correct link. I use:
class Node {
public:
int value;
Node* next;
Node* prev;
public:
Node() {}
void set_value(int x) { value = x; }
void set_next(Node* x) { next = x; }
void set_prev(Node* x) { prev = x; }
Node* get_next() { return next; }
Node* get_prev() { return prev; }
};
class deque {
public:
Node* head;
Node* tail;
public:
deque() { head = NULL; tail = NULL; }
void push(int x) {
Node* n = new Node();
n->set_value(x);
n->set_next(NULL);
n->set_prev(NULL);
Node* t = head; //link to the next node
if (t == NULL) {
head = n;
} else {
while (t->get_next() != NULL) {
t = t->get_next();
}
t->set_next(n);
}
}
};
As I have tested the part that connects a node to the next one works fine but I am having some troubles connecting the node to the previous one. One that comes in mind is a variation of the first one:
Node* t = tail;
if (t == NULL) {
tail = n;
} else {
while (t->get_prev() != NULL) {
t = t->get_prev();
}
t->set_prev(n);
}
But by using this, the tail node is always the current n node if only the node n is the one and only node in the queue... What should I do? thanks a lot
Drawing always helps with such data structures. What you have currently:
You correctly set t's next with: t->set_next(n);. What is missing is the arrow underneath it, and it's: n->set_prev(t).
In general, when dealing with doubly-linked lists, a call to set_next should always (most of the time) be accompanied by a call to set_prev on set_next's argument. It's because of the doubly-linked list's property:
x->next == y implies y->prev == x, and y->prev == x implies x->next == y.