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

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.

Related

Unable to create or return Reversed Linked list

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

remove item on linked list

I have implemented a linked list but I find that removal of the last element in the linked list always fails. I checked my code several times but didn't find the logic mistake. Remove from the head and middle node works fine. Below is my code:
#include<iostream>
using namespace std;
template<typename T>
class Node{ //
private:
T val;
Node *next;
Node *prev;
public:
Node(T value){
val = value;
next = nullptr;
prev = nullptr;
}
~Node(){
if(prev != nullptr){
prev->next = next;
}
if(next != nullptr){
next->prev= prev;
}
}
T& getVal(){ //
return val;
}
Node* getNext(){
return next;
}
Node* getPrev(){
return prev;
}
//insert node after this node
void insert(Node *n){
if(next != nullptr){
next->prev = n;
}
n->next = next;
n->prev = this;
next = n;
}
void deleteNode(){
if(prev != nullptr && next != nullptr){
prev->next = next;
next->prev = prev;
}
}
};
//build a linked list with deletion and push back function
template<typename T>
class LList{
private:
Node<T> *head;
Node<T> *tail;
public:
LList(){
head = nullptr;
tail = nullptr;
}
~LList(){
if(nullptr != head){
while(head->getNext() != nullptr){ //
delete head->getNext();
}
delete head;
}
}
void push_back(T val){
Node<T>* n = new Node<T>(val);
if(head == nullptr){
head = n ;
tail = head;
}
else{
tail->insert(n);
tail = n;
}
}
void deleteItem(T item){
Node<T> *node = head;
//delete head
if(node->getVal() == item){
head = node->getNext();
node->deleteNode();
return;
}
//delete middle and tail
while(node->getVal() != item && node->getNext() != nullptr ){
node = node->getNext();
}
if(node->getVal() == item && node == tail){
tail = node->getPrev();
node->deleteNode();
return;
}
if(node->getVal() == item && node != tail){
node->deleteNode();
return;
}
else {
cout<<"didnt find the item "<<item<<endl;
}
}
void print(){
Node<T> *node = head;
while(node->getNext() != nullptr){
cout<<node->getVal()<<endl;
node = node->getNext();
}
cout<<node->getVal()<<endl;
}
};
int main(){
LList<double> list;
list.push_back(3.13);
list.push_back(2.8);
list.push_back(23);
list.push_back(4);
list.print();
list.deleteItem(3.13);
list.deleteItem(2);
list.deleteItem(4);
list.print();
return 0;
}
Here it is:
void deleteNode(){
if(prev != nullptr && next != nullptr){
prev->next = next;
next->prev = prev;
}
}
};
For the last element i guess that next equals nullptr and so the whole condition fails.
What I don't understand, is why removing the first element doesn't fail too, you probably should x-check your code for this.
[edit]
Here's my solution to fix this bug, it's basically the same as in the destructor for node:
void deleteNode(){
if(prev != nullptr){
prev->next = next;
}
if(next != nullptr){
next->prev= prev;
}
};
I think all cases have been considered in this:
Head := prev == null & next->prev = nullptr (assuming prev for this node was nullptr before)
Middle := prev->next = next & next->prev = prev
Tail := prev->next = null (assuming as above) & next == null
Head&Tail := prev == null & next == null (Only element of the list is deleted, so no references to be changed)
[/edit]

Moving first item in linked list to end C++

I need to move the first item in a linked list to the end of the list. My problem is I'm going in to an infinite loop. When I remove the cause for the infinite loop (tail -> link != NULL; in the for loop), I get a seg fault. So, looking for ideas on how to get this code to work.
#include <iostream>
#include <string>
using namespace std;
struct Node
{
string data;
Node *link;
};
class Lilist
{
public:
Lilist() {head = NULL;}
void add(string item);
void show();
void move_front_to_back();
Node* search(string target);
private:
Node *head;
};
int main()
{
Lilist L1, L2;
string target;
L1.add("Charlie"); //add puts a name at the end of the list
L1.add("Lisa");
L1.add("Drew");
L1.add("Derrick");
L1.add("AJ");
L1.add("Bojian");
cout << "Now showing list One:\n";
L1.show(); // displays the list (This function displayed the list properly)
cout << "\n";
L1.move_front_to_back();
L1.move_front_to_back();
L1.show();
cout << "\n";
return(0);
}
void Lilist::add(string item)
{
Node *temp;
if(head == NULL)
{
head = new Node;
head -> data = item;
head -> link = NULL;
}
else
{
for(temp = head; temp -> link != NULL; temp = temp -> link)
;
temp -> link = new Node;
temp = temp -> link;
temp -> data = item;
temp -> link = NULL;
}
}
void Lilist::show()
{
for(Node *temp = head; temp != NULL; temp = temp -> link)
std::cout << temp -> data << " ";
}
void Lilist::move_front_to_back()
{
Node *temp;
Node *tail;
temp = head;
for(tail = head; tail != NULL; tail = tail -> link)
;
head = head -> link;
tail -> link = temp;
temp -> link = NULL;
}
The problem is in how you compute tail. Notice this (unrelated lines omitted for brevity):
for(tail = head; tail != NULL; tail = tail -> link)
;
tail -> link = temp;
Notice that the for loop will only terminate once tail is NULL. Then, you dereference tail ... which is null.
So change the for loop condition:
for (tail = head; tail->link != NULL; tail = tail->link)
;
This will find the last element in the list, instead of flowing off the end.
[Live example]
Angew already explained why your original code was failing. I would suggest an alternative approach - give Lilist a tail member that is managed alongside its head member. Then you don't have to hunt for the tail whenever you need it, you always know exactly which Node is the current tail, eg:
#include <iostream>
#include <string>
using namespace std;
struct Node
{
string data;
Node *next;
Node(string s);
};
class Lilist
{
public:
Lilist();
~Lilist();
void add(string item);
void show();
void move_front_to_back();
Node* search(string target);
private:
Node *head;
Node *tail;
};
Node::Node(string s)
: data(s), next(NULL)
{
}
Lilist::Lilist()
: head(NULL), tail(NULL)
{
}
Lilist::~Lilist()
{
for(Node *temp = head; temp != NULL; temp = temp->next)
delete temp;
}
void Lilist::add(string item)
{
Node *temp = new Node(item);
if (head == NULL)
head = temp;
if (tail != NULL)
tail->next = temp;
tail = temp;
}
void Lilist::show()
{
for(Node *temp = head; temp != NULL; temp = temp->next)
cout << temp->data << " ";
}
void Lilist::move_front_to_back()
{
if (head == tail)
return;
Node *temp = head;
head = temp->next;
temp->next = NULL;
tail->next = temp;
tail = temp;
}
Node* Lilist::search(string target)
{
for(Node *temp = head; temp != NULL; temp = temp->next)
{
if (temp->data == target)
return temp;
}
return NULL;
}

Sorted queue linked list c++

I need to make a queue linked list in which the first node always has the smallest value , so it needs to be sorted , I have written this code :
#include <iostream>
using namespace std;
struct Node
{
int key;
Node *link;
};
class qlinkedlist
{
private:
Node *head;
Node *tail;
Node *curr;
Node *prev;
int count;
public:
void Enqueue(int value)
{
Node *newnode = new Node;
newnode -> key = value;
newnode -> link = NULL;
if(head==NULL)
{
head=tail=newnode;
count++;
}
else if(newnode->key < head->key)
{
newnode -> link = head;
head = newnode;
count++;
}
else
{
prev=head;
curr=head->link;
while(curr != NULL)
{
if(newnode->key < curr->key)
{
prev->link = newnode;
newnode->link = curr;
count++;
}
else
{
prev = curr;
curr = curr ->link;
}
}
}
}
void Dequeue()
{
if(head==NULL)
{
cout<< "Queue is empty" << endl;
}
else
{
curr = head;
head = head -> link;
delete curr;
count--;
}
}
void print()
{
curr = head;
while (curr!=NULL)
{
cout << curr -> key << endl;
curr = curr -> link;
}
}
};
void main()
{
qlinkedlist obj;
obj.Enqueue(5);
obj.Enqueue(4);
obj.Enqueue(3);
obj.Enqueue(2);
obj.Enqueue(1);
obj.print();
}
problem is it works only if I add nodes in the above order , for example if I try to add the 3 then 2 then 5 it does not work , what's wrong with the code ?
Thank you
Because if you try to add an element that is bigger than everything you have in the list, it will never pass your only condition to add a node: if(newnode->key < curr->key). Try this instead:
while(curr != NULL && newnode->key > curr->key)
{
prev = curr;
curr = curr ->link;
}
prev->link = newnode;
newnode->link = curr;
count++;
This way, you go through the linked list until you find the right spot, then add the new node even if you get to the end (curr==NULL).

segmentation fault when I'm trying to print my list through my function

I know this is probably trivial to the c++ programmer, but I'm a noobie trying to figure this out. In my main, if I print my short list manually(cout << head->value etc) it works, but when I use my print function I get a segmentation fault. I've been trying to use a debugger, but I'm not very good at unix/c++ and I'm getting frustrated trying to figure this out.
#include <iostream>
using namespace std;
class ListNode
{
public:
int value;
ListNode* next;
};
void insertAtHead(ListNode** head, int value)
{
ListNode *newNode = new ListNode;
newNode->value = value;
if(head == NULL)
{
*head = newNode;
newNode->next = NULL;
}
else
{
newNode->next = *head;
*head = newNode;
}
}
void printList(ListNode* head)
{
while(head != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
//inserts after the node with given value
void insertAfterNode(ListNode** head,ListNode** newNode, int value)
{
ListNode* current = *head;
while(current != NULL && (current->value != value))
{
//cout << "Im Here";
current = current->next;
cout << current->value;
}
(*newNode)->next = current->next;
current->next = *newNode;
}
int main()
{
ListNode *head;
insertAtHead(&head, 5);
insertAtHead(&head, 10);
ListNode* newNode = new ListNode;
newNode->value = 8;
newNode->next = NULL;
insertAfterNode(&head,&newNode, 5);
printList(head);
}
Check this modifications in your functions
void insertAtHead(ListNode** head, int value)
{
ListNode *newNode = new ListNode;
newNode->value = value;
newNode->next = *head;
*head = newNode;
}
void printList(const ListNode* head)
{
while(head != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
In insertAtHead you are pasing a double pointer, so comparison should be like this.
Added checking for whether *head is null before accessing. and if null adding new node as head
void insertAfterNode(ListNode** head,ListNode** newNode, int value)
{
ListNode* current = *head;
if (current != NULL)
{
while(current != NULL && (current->value != value))
{
//cout << "Im Here";
current = current->next;
cout << current->value;
}
(*newNode)->next = current->next;
current->next = *newNode;
}
else
{
*head = *newNode;
}
}
And in main intialise head before use
int main()
{
ListNode *head = NULL;
insertAtHead(&head, 5);
printList(head); // <== note: by-value, not by address or reference.
You need to check if the next value you are trying to access is not null like this :
void printList(ListNode* head)
{
if (head != NULL)
{
while(head->next != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
}
Dude the first answer is correct
But i would like to make another correction
In your while loop in function insert after node
current!=NULL is incorrect because then your condition will be true if and only if the last node in the list matches the value of 5
Condition should be just while(current->value!=value)
by this you will reach the node having value 5