Unable to create or return Reversed Linked list - c++

Here using the function returnReverseLinkedList I am returning the reversed linked list of the given linked list. But the problem with this approach is that i lose the original linked list. So I make another fucntion called createReversedLinkedList to make a copy of the original linked list and reverse the copy and maintain possession of both.
unfortunately createReversedLinkedList is giving Runtime error.
obviously my end goal is to check if the given linked list is palindrome or not. This issue is just a stepping stone.
Could someone tell me why?
//Check if a linked list is a palindrome
#include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
node(int data)
{
this->data = data;
this->next = NULL;
}
};
node *returnReverseLinkedList(node *head)
{
// Will Lose original Linked List
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return head;
node *prev = NULL;
node *curr = head;
node *tempNext = head->next;
while (tempNext != NULL)
{
curr->next = prev;
prev = curr;
curr = tempNext;
tempNext = tempNext->next;
}
curr->next = prev;
return curr;
}
node *createReversedLinkedList(node *head)
{
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return NULL;
else
{
node *temp = head;
node *newHead = NULL;
node *newTail = NULL;
while (temp != NULL)
{
node *newNode = new node(temp->data);
if (newHead == NULL)
{
newHead = newNode;
newTail = newNode;
}
else
{
newTail->next = newNode;
newTail = newNode;
}
}
return returnReverseLinkedList(newHead);
}
}
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head);
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false;
cout << "debug 2" << endl;
original = original->next;
reverse = reverse->next;
}
return true;
}
// #include "solution.h"
node *takeinput()
{
int data;
cin >> data;
node *head = NULL, *tail = NULL;
while (data != -1)
{
node *newnode = new node(data);
if (head == NULL)
{
head = newnode;
tail = newnode;
}
else
{
tail->next = newnode;
tail = newnode;
}
cin >> data;
}
return head;
}
void print(node *head)
{
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
int main()
{
node *head = takeinput();
node *revese2 = createReversedLinkedList(head);
print(revese2);
// bool ans = check_palindrome(head);
// if (ans)
// cout << "true";
// else
// cout << "false";
// return 0;
}

As asked by the OP, building a reversed linked is simply done by building as you would a stack (e.g LIFO) rather than duplicating the same original forward chain. For example:
node *createReversedLinkedList(const node *head)
{
node *newHead = NULL;
for (; head; head = head->next)
{
node *p = new node(head->data)
p->next = newHead;
newHead = p;
}
return newHead;
}
Note we're not hanging our copied nodes on the tail of the new list; they're hanging on the head of the new list, and becoming the new head with each addition. That's it. There is no need to craft an identical list, then reverse it; you can reverse it while building the copy to begin with.
A note on the remainder of your code. You have a dreadful memory leak, even if you fix the reversal generation as I've shown above. In your check_palindrome function, you never free the dynamic reversed copy (and in fact, you can't because you discard the original pointer referring to its head after the first traversal:
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head); // only reference to reversed copy
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false; // completely leaked entire reversed copy
original = original->next;
reverse = reverse->next; // lost original list head
}
return true;
}
The most obvious method for combating that dreadful leak is to remember the original list and use a different pointer to iterate, and don't leave the function until the copy is freed.
bool check_palindrome(const node *head)
{
bool result = true;
node *reverse = returnReverseLinkedList(head);
for (node *p = reverse; p; p = p->next, head = head->next)
{
if (p->data != head->data)
{
result = false;
break;
}
}
while (reverse)
{
node *tmp = reverse;
reverse = reverse->next;
delete tmp;
}
return result;
}

Related

Deleting a key from a circular linked list

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);
}
}

Adding a node to the end of a linked list but not able to access the last node

I have been having troubles adding a new node at the end of a singly linked-list.
When I print the list out, I don't seem to be able to access the last node.
if (head == nullptr)
{
head = newNode;
}
else
{
record* current = head;
while (current->next != nullptr)
{
current = current->next;
}
current->next = newNode;
}
//Writing data to record.
newNode->name = name;
newNode->highscore = highscore;
newNode->initials = initials;
newNode->plays = plays;
newNode->revenue = revenue;
record* test = head;
while (test->next != nullptr)
{
cout << test->name << endl;
test = test->next;
}
You need to add nullptr after adding a new node to the list. Also, you should print the list till you reach nullptr
if (head == nullptr)
{
head = newNode;
}
else
{
record* current = head;
while (current->next != nullptr)
{
current = current->next;
}
current->next = newNode;
newNode->next = nullptr;
}
//Writing data to record.
newNode->name = name;
newNode->highscore = highscore;
newNode->initials = initials;
newNode->plays = plays;
newNode->revenue = revenue;
record* test = head;
while (test != nullptr)
{
cout << test->name << endl;
test = test->next;
}
While the other answer is good and necessary, I think it can be handled in a simpler manner. Here's an example Node.
struct Node {
int data;
Node* next = nullptr;
Node(int val) : data(val) {}
}
By default-initializing the pointer to nullptr, you don't have to constantly worry about it throughout your list class implementation. Every declared Node will automatically set the pointer to nullptr for you.

Why is this if statement triggered in this C++ code?

This code is supposed to reverse a linked list. The following code returns an empty linked list even when provided with a non empty list.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
While this code strangely works where I added a cout statement just to check if the else was triggered.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
cout << "Triggered";
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
Can someone please explain why this is happening?
Pretty simple, you have to initialize the pointers, else it leads to unexpected behavior that includes not showing it at all or just showing it if an initialized cout is triggered - but it doesn't have to do anything and that's up to your compiler implementation.
//cpp17
listNode* curr{}, *prev{}, *next{};
//before
listNode* curr = nullptr, *prev = nullptr, *next = nullptr;
It is still not in the reverse order as you intended to do.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
listNode* curr{}, *prev{}, *next{};
//ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (next != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
cheers :)
Like mentioned before I found time to write a solution for an other approach of solving your problem to reverse a linked list via class. For a better understanding for beginners I skipped the rule of three/five and initialized the list in the main function and not via constructor in the class:
#include <iostream>
class listElement
{
std::string data;
listElement* next;
listElement* last;
public:
void setData(std::string);
void append(std::string);
void displayElements();
void reverseDisplayElements(listElement*);
void freeMemory();
listElement* reverseList(listElement*);
};
void listElement::setData(std::string newData)
{
last = this;
data = newData;
next = nullptr;
}
void listElement::append(std::string newData)
{
// Double linked list
// last->next = new listElement();
// last->next->data = newData;
// last->next->next = nullptr;
// last = last->next;
// Singly linked list
//has next the value nullptr?
//If yes, next pointer
if (next == nullptr)
{
next = new listElement();
next->data = newData;
next->next = nullptr;
}
//else the method again
else
next->append(newData);
}
listElement* listElement::reverseList(listElement* head)
{
//return if no element in list
if(head == nullptr)
return nullptr;
//initialize temp
listElement* temp{};
while(head != nullptr){
listElement* next = head->next;
head->next = temp;
temp = head;
head = next;
}
return temp;
}
void listElement::displayElements()
{
//cout the first entry
std::cout << data << std::endl;
//if the end is not reached, call method next again
if (next != nullptr)
next->displayElements();
}
void listElement::reverseDisplayElements(listElement*head)
{
//recursiv from the last to the list beginning - stop
listElement *temp = head;
if(temp != nullptr)
{
if(temp->next != nullptr)
{
reverseDisplayElements(temp->next);
}
std::cout << temp->data << std::endl;
}
}
void listElement::freeMemory()
{
//If the end is not reached, call the method again
if (next != nullptr)
{
next->freeMemory();
delete(next);
}
}
int main ()
{
//Pointer to the Beginning of the list
listElement* linkedList;
//Creating the first element
linkedList = new listElement();
//Write data in the first element
linkedList->setData("Element 1");
//add more elements
linkedList->append("Element 2");
linkedList->append("Element 3");
linkedList->append("Element 4");
//display list
linkedList->displayElements();
//space divider
std::cout << "\nPrint in reverse order:" << std::endl;
//display list in reverse order
//pass list beginning as stop point
linkedList->reverseDisplayElements(linkedList);
std::cout << std::endl;
linkedList->displayElements();
std::cout << "\nReverse elements:" << std::endl;
linkedList = linkedList->reverseList(linkedList);
linkedList->displayElements();
std::cout << std::endl;
//destruct the list and free memory
linkedList->freeMemory();
delete(linkedList);
return 0;
}
Btw. there are many different solutions for that task.

insert at end of linked list

I am writing a simple function to insert at the end of a linked list on C++, but finally it only shows the first data. I can't figure what's wrong. This is the function:
node* Insert(node* head, int data)
{
if (head == NULL) {
head = new node();
head->data = data;
head->link = NULL;
return head;
}
else {
node* temp = head;
while (temp != NULL) {
temp = temp->link;
}
node* temp2 = new node();
temp2->data = data;
temp2->link = NULL;
(temp->link) = temp2;
return head;
}
}
Change the condition in while construct from:
while (temp!=NULL) {
temp=temp->link;
}
To
while (temp->link!=NULL) {
temp=temp->link;
}
In statement, temp->link = temp2, temp is a null pointer. You were dereferencing a NULL pointer.
To append a node at the back, temp pointer should point to the last node of the linked list. So, in the while loop, you need to just stop linked list traversal when you have reached the last node, i.e, the node whose link member points to nothing (has NULL). while (temp->link!=NULL) will stop at the last node as last node will have link member pointing to NULL.
You can simplify your logic by doing this:
void Insert(node **pnode, int data)
{
while (*pnode) {
pnode = &(*pnode)->link;
}
*pnode = new node(data, NULL);
}
assuming you have a node constructor that initializes data and link from arguments.
Instead of calling it as
head = Insert(head, 42);
you'd now do
Insert(&head, 42);
change while(temp!=NULL) to while(temp->link!=NULL)
node* Insert(node* head, int data)
{
if (head == NULL) {
head = new node();
}
else {
while (head->link != NULL) {
head = head->link;
}
head = head->link = new node();
}
head->data = data;
head->link = NULL;
return head;
}

Ordered Linked List errors

I know all of the code isn't working but when I first run the program and the first string is read in from the text field the program errors out.The main function is passing the string to "Insert list function" in the implementation.
The program is suppose to insert a node every time that a string is read in from the text file. The program call also call the delete function which i know isn't working yet(that is why it is commented out). I am just trying to find the error that is created when the insert function is called. The main function has a while loop that creates a Node for every text entry and passes the node one by one to be sorted in ABC order.
Header file:
#include <string>
using namespace std;
struct Node
{
string data;
Node * next;
};
class List
{
public:
List();
~List();
bool Insert(string);
bool Delete(string);
void Print();
bool Edit(string, string);
private:
Node * head;
Node * cur;
Node * trailer;
};
Implementation:
#include <iostream>
#include <string>
#include <fstream>
#include "List.h"
using namespace std;
List::List():head(NULL)
{}
List::~List()
{}
bool List::Insert(string data)
{
Node* newNode = new Node;
if (newNode == NULL)
{
cout << "Error: Memory Allocation Failed" << endl;
return false;
}
newNode->data = data;
cur = head;
trailer = NULL;
if (head == NULL)
{
//cout << "head is Null" << endl;
head = newNode;
cout << head -> data << endl;
newNode->next = NULL;
//return true;
}
while (newNode->data > cur->data && cur -> next != NULL)
{
trailer = cur;
cur = cur->next;
}
if (cur->next == NULL)
{
cur->next = newNode;
newNode->next = NULL;
return true;
}
else
{
trailer->next = newNode;
newNode->next = cur;
return true;
}
}
bool List::Delete(string data)
{
/*Node *temp = head->next;
while (head != NULL)
{
delete head;
head = temp;
temp = head->next;
}
return true;*/
}
bool List::Edit(string dataDelete, string dataInsert)
{
Delete(dataDelete);
Insert(dataInsert);
return true;
}
void List::Print()
{
for (Node * Count = head; Count != NULL; Count = Count->next)
{
cout << Count->data << endl;
}
}
#Deepak is right, the problem is when you're inserting first element the head variable is NULL and cur is set to the value of head.
To fix it you can simply place
cur = head;
trailer = NULL;
after condition
if (head == NULL)
{
//cout << "head is Null" << endl;
head = newNode;
cout << head -> data << endl;
newNode->next = NULL;
//return true;
}
Also there will be an error when you will try to insert element that should be placed in the beggining (value that is smaller than any other value in the list). It will happen when condition of the loop
trailer = NULL;
while (newNode->data > cur->data && cur -> next != NULL) { ... }
is false in the first call, so trailer will be NULL. To fix it you will need to check trailer variable, like this
if (trailer == NULL) {
newNode->next = head;
head = newNode;
return true;
}
As the result your code of Insert will look like
bool List::Insert(string data)
{
Node* newNode = new Node;
if (newNode == NULL)
{
cout << "Error: Memory Allocation Failed" << endl;
return false;
}
newNode->data = data;
if (head == NULL)
{
head = newNode;
newNode->next = NULL;
return true;
}
cur = head;
trailer = NULL;
while (newNode->data > cur->data && cur -> next != NULL)
{
trailer = cur;
cur = cur->next;
}
if (trailer == NULL) {
newNode->next = head;
head = newNode;
return true;
}
if (cur->next == NULL)
{
cur->next = newNode;
newNode->next = NULL;
return true;
}
else
{
trailer->next = newNode;
newNode->next = cur;
return true;
}
}
While inserting the first node you are getting error because of
while (newNode->data > cur->data && cur -> next != NULL)
At this moment value in the cur is NULL and you are trying to access cur->data.