Merge sort a Linked list (segementation fault) - c++

The below code is for merge sorting a linked list. Its giving out a segmentation fault. I really dont know how to deal with the above. All I could find was that I was trying to access a restricted part of the memory, the only place I think i could've gone wrong is re combining the two linked lists after splitting and sorting them under the split function body. I'd appreciate if I could get some guidance on how to deal with segmentation faults from here on & how to rectify them.
//Segmentation fault
#include <iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int data)
{
this->data = data;
next = NULL;
}
};
void print(Node *head)
{
Node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
}
Node *insert()
{
int data;
cin >> data;
Node *head = NULL;
Node *tail = NULL;
while (data != -1)
{
Node *n = new Node(data);
if (head == NULL)
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = tail->next;
}
cin >> data;
}
return head;
}
Node *sortedMerge(Node *h1, Node *h2)
{
// Node *fHead = NULL;
// Node *fTail = NULL;
if (!h1)
{
return h2;
}
if (!h2)
{
return h1;
}
if (h1->data < h2->data)
{
h1->next = sortedMerge(h1->next, h2);
return h1;
}
else
{
h2->next = sortedMerge(h1, h2->next);
return h2;
}
}
void split(Node *head, Node *h1, Node *h2)
{
Node *slow = head;
Node *fast = head->next;
while (fast != NULL)
{
fast = fast->next;
if (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}
h1 = head;
h2 = slow->next;
slow->next = NULL;
}
void mergeSort_LL(Node *head)
{
Node *temp = head;
Node *h1;
Node *h2;
if ((temp == NULL) || (temp->next == NULL))
{
return;
}
split(temp, h1, h2);
mergeSort_LL(h1);
mergeSort_LL(h2);
head = sortedMerge(h1, h2);
}
int main()
{
Node *head = insert();
print(head);
cout << endl;
mergeSort_LL(head);
cout << "Sorted List is : " << endl;
print(head);
return 0;
}

Your call to split will not make h1 or h2 get a value. Arguments are passed by value. Since you evidently need h1 and h2 to get a different value from that split call, you should pass their addresses:
split(temp, &h1, &h2)
The function itself should therefore accept these addresses instead of the node pointers themselves:
void split(Node *head, Node **h1, Node **h2) {
// ...
*h1 = head;
*h2 = slow->next;
// ...
}

Related

How to use head while iterating through a linked list?

We are iterating through the linked list with the help of head, that is, we are updating our head as we move forward towards i th position. Please have a look at the fuction insertIthnode. I am inserting my Node at i th position are returning head - and it's still able to print the linked list. I don't know how? head is no longer pointing towards the first node then how is it still able to return a full linked list?
here's the code:
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *next;
Node(int data) {
this->data = data;
next = NULL;
}
};
int length(Node *head) {
int x = 0;
Node *temp = head;
while (temp != NULL) {
x += 1;
temp = temp->next;
}
return x;
}
void printIthnode(Node *head, int i) {
int n = length(head);
if (i < 0 || i > n - 1) {
cout << -1 << endl;
return;
}
int count = 1;
while (count <= i) {
head = head->next;
count++;
}
if (head) {
cout << head->data << endl;
} else {
cout << "-1" << endl;
}
}
Node *takeinput() {
int data;
cin >> data;
Node *head = NULL;
Node *tail = NULL;
while (data != -1) {
Node *n = new Node(data);
if (head == NULL) {
head = n;
tail = n;
} else {
tail->next = n;
tail = n;
}
cin >> data;
}
return head;
}
void PrintLL(Node *head) {
Node *temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
}
Node *insertIthnode(Node *head, int i, int data) {
if (i < 0) {
return head;
} else if (i == 0) {
Node *n = new Node(data);
n->next = head;
head = n;
return head;
}
int count = 1;
while (count <= i - 1 && head != NULL) {
head = head->next;
count++;
if (count == i - 1) {
Node *n = new Node(data);
n->next = head->next;
head->next = n;
return head;
}
return head;
}
}
int main() {
/*Node n1(1);
Node *head=&n1;
Node n2(2);
Node n3(3);
Node n4(4);
Node n5(5);
Node n6(6);
n1.next=&n2;
n2.next=&n3;
n3.next=&n4;
n4.next=&n5;
n5.next=&n6;
*/
Node *head = takeinput();
insertIthnode(head, 3, 7);
PrintLL(head);
}
In the main() function you are creating a head when you are taking input from the user with the help of the "takeInput()" function.
After that, you are calling the function "insertIthnode(head,3,7)" which is returning the head (since the return type is Node) but you are not receiving it in any variable so the head returned from the "insetIthnode" is lost.
Your original head remains the same as per of "takeInput()" function.
If you try to insert ith Node at Index 0 it won't print according to the inserted node.
The problem is that you consider the Node as the linked list. While this is valid, the whole point of the linked list is that you don't lose track of the head. You could use two approaches:
Don't iterate over the head. Instead, use a temporary reference to the head.
Implement a Linked List wrapper. You can keep a constant reference to the head while performing operations over the node.
You pass head by value. Any changes you do to the variable receiving the value of head inside the functions are made to the local variable inside the function only and will not be visible from the call site.
Take your PrintLL function as an example:
void PrintLL(Node *head) { // head is here a local variable
Node *temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
}
This could be rewritten without the extra variable temp. The name head doesn't make it the same head you used to call the function with:
void PrintLL(Node* head) {
while (head != nullptr) {
cout << head->data << ' ';
head = head->next;
}
}
and it would not affect the head you passed in as a parameter.
Similarly:
void foo(int x) {
++x;
//
}
int main() {
int x = 10;
foo(x);
std::cout << x << '\n'; // prints 10
}

How to use point to next node when deleting elements in C++

I have previously posted some part of this task here.
I am now implementing a method that removes an element at a given index. My code is
void remove(int index)
{
if (head != NULL)
{
Node *current = get_node(index);
Node *prev = get_node(index - 1);
Node *next = get_node(index + 1);
prev->next = current->next;
delete current;
}
}
however, I am facing this error message
libc++abi.dylib: terminating with uncaught exception of type
std::range_error: IndexError: Index out of range
Abort trap: 6
I am guessing the problem is the pointers, but I am not sure why this is not working. Anyone who can help?
I think you can handle corner cases like this:
#include <iostream>
using namespace std;
struct Node {
Node(int val) {
this->val = val;
}
struct Node * next;
int val;
};
class LinkedList {
public:
Node* head;
LinkedList() {
head = new Node(1);
Node * n1 = new Node(2);
head->next = n1;
Node * n2 = new Node(3);
n1->next = n2;
}
void remove(int index) {
if (head == NULL) {
return;
}
int pos = 0;
Node * cur = head;
Node *prev = NULL;
while (cur != NULL) {
if (pos == index) {
break;
}
pos++;
prev = cur;
cur = cur->next;
}
if (prev == NULL) {
head = head->next;
}
else {
prev->next = cur->next;
}
delete cur;
}
};
void print(Node * head){
cout << "Current linked list:\n";
while(head != NULL) {
cout << head->val << endl;
head = head->next;
}
cout << endl;
}
int main() {
LinkedList * list = new LinkedList();
print(list->head);
list->remove(0);
print(list->head);
list->remove(1);
print(list->head);
list->remove(0);
print(list->head);
}

Reversing LinkedList result in wrong links by recursion

I wrote the following code to reverse a linked list recursively for my homework. However, It's not connecting the links properly. Can please someone tell me what's wrong in the following reverse function? I have tried GDB as well. But, could not figure out what's wrong?
#include <iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
explicit Node(int data)
{
this->data = data;
next = nullptr;
}
};
void pushBack(Node * &head, Node * &tail, int data)
{
if(head == nullptr)
{
head = new Node(data);
tail = head;
}
else
{
tail->next = new Node(data);
tail = tail->next;
}
}
void printList(Node *head)
{
if(head == nullptr)
return;
cout << head->data << " ";
printList(head->next);
}
void reverseListRecursive(Node * &head)
{
if(head->next == nullptr)
{
return;
}
reverseListRecursive(head->next);
head->next->next = head;
head->next = nullptr;
}
int main()
{
int cap;
cin >> cap;
Node *head = nullptr, *tail = nullptr;
for(int i = 0; i < cap; ++i)
{
int element;
cin >> element;
pushBack(head, tail, element);
}
reverseListRecursive(head);
printList(head);
return 0;
}
Head is being passed by reference and also the infinite recursion is also not there.
The problem is that the head pointer needs to point to the last node of the linked list. Following code fixes the problem.
void reverseListRecursive(Node * &head, Node *temp = nullptr)
{
if(temp == nullptr)
temp = head;
if(temp->next == nullptr)
{
head = temp;
return;
}
reverseListRecursive(head, temp->next);
temp->next->next = temp;
temp->next = nullptr;
}

deleting a linked list node, C++ function not working

#include <iostream>
using namespace std;
class List {
public:
struct node {
int data;
node *next;
};
node* head = NULL;
node* tail = NULL;
node* temp = NULL;
node* prev = NULL;
public:
void addNum(int num) {
temp = new node;
temp->data = num;
temp->next = NULL;
if (head == NULL) {
head = temp;
tail = temp;
}
else {
tail->next = temp;
tail = temp;
}
}
void PrintList() {
temp = head;
while (temp != NULL) {
cout << temp->data << endl;
temp = temp->next;
}
}
void DelNum(int num) {
temp = head;
while (temp != NULL) {
if (temp->data == num) {
prev->next = temp->next;
free(temp);
}
temp = prev;
temp = temp->next;
}
}
};
int main() {
List list;
list.addNum(1);
list.addNum(2);
list.addNum(3);
list.addNum(4);
list.addNum(5);
list.addNum(6);
list.DelNum(3);
list.PrintList();
return 0;
}
What is wrong with my DelNum function? When I run the program nothing pops up. Doesn't matter what number I put in.
As mss pointed out the problem is in your DelNum() function where you assign temp = prev;. In your initialization you defined that node* prev = NULL; So, prev = NULL at the point when you assigned it to temp which caused segmentation fault when you try to use it like temp = temp->next;.
Two main problems are there in DelNum function:
first, when you are in while loop
, you should assign
prev = temp;
second, when you have found your target element, after deleting it you have to break out of the loop, which isn't done in your code
below is your corrected code( also correction of some other corner case in DelNum function ):
#include <iostream>
using namespace std;
class List {
public:
struct node {
int data;
node *next;
};
node* head = NULL;
node* tail = NULL;
node* temp = NULL;
node* prev = NULL;
public:
void addNum(int num) {
temp = new node;
temp->data = num;
temp->next = NULL;
if (head == NULL) {
head = temp;
tail = temp;
}
else {
tail->next = temp;
tail = temp;
}
cout<<num<<" is added \n";
}
void PrintList() {
temp = head;
while (temp != NULL) {
cout << temp->data << endl;
temp = temp->next;
}
}
void DelNum(int num) {
if(head==NULL)//empty
{
cout<<"empty linked list, can't be deleted\n";
return;
}
if(head->next==NULL)//means only one element is left
{
if(head->data==num)
{
node * fordelete=head;
head=NULL;
cout<<num<<"is deleted\n";
delete(fordelete);
}
else
{
cout<<"not found , can't be deleted\n";
}
return;
}
temp = head; // when more than one element are there
prev = temp;
while (temp != NULL) {
if (temp->data == num) {
prev->next = temp->next;
free(temp);
cout<<num<<" is deleted\n";
break;
}
prev= temp;
temp = temp->next;
}
if(temp==NULL)
{
cout<<"not found, can't be deleted\n";
}
}
};
int main() {
List list;
list.addNum(1);
list.addNum(2);
list.addNum(3);
list.addNum(4);
list.addNum(5);
list.addNum(6);
list.PrintList();
list.DelNum(3);
list.DelNum(7);
list.PrintList();
return 0;
}
I hope it will help you.

simple linked list delete fails

I'm learning C++, I try to implement simple singly linked list but the delete node part fails. I could not comprehend why this basic delete_node part is failing. It seems prev->set_next line in delete_node method does not working correctly. I tried to debug it too but failed to spot the error.
using namespace std; //ignore it for simplicity
class Node {
int data;
Node *next;
public:
Node() {}
void set_data(int a_data)
{
data = a_data;
}
void set_next(Node *a_next)
{
next = a_next;
}
int get_data()
{
return data;
}
Node* get_next()
{
return next;
}
};
class List {
Node *head;
public:
List()
{
head = NULL;
}
void print_list();
void append_node(int data);
void delete_node(int data);
};
void List::print_list()
{
Node *temp = head;
if(temp == NULL)
{
cout << "empty" << endl;
return;
}
if(temp->get_next() == NULL)
{
cout << temp->get_data() << "--->";
cout << "NULL" << endl;
}
else
{
do
{
cout << temp->get_data() << "+++>";
temp = temp->get_next();
} while(temp != NULL);
cout << "NULL" << endl;
}
}
void List::append_node(int data)
{
Node *new_node = new Node();
new_node->set_data(data);
new_node->set_next(NULL);
Node *temp = head;
if(temp != NULL)
{
while(temp->get_next()!=NULL)
{
temp = temp->get_next();
}
temp->set_next(new_node);
}
else
{
head = new_node;
}
}
void List::delete_node(int data)
{
Node *temp = head;
if(temp == NULL)
{
return;
}
else
{
Node *prev = NULL;
do
{
prev = temp;
if(temp->get_data() == data)
{
prev->set_next(temp->get_next());
delete temp;
break;
}
temp = temp->get_next();
} while(temp!=NULL);
}
}
int main()
{
List list;
list.append_node(10);
list.append_node(20);
list.append_node(30);
list.append_node(40);
list.append_node(50);
list.append_node(60);
list.delete_node(30); //
list.print_list();
return 0;
}
valgrind gives me following error.
==22232== Invalid read of size 8
==22232== at 0x400D38: Node::get_next() (20_1.cpp:25)
==22232== by 0x400A5E: List::print_list() (20_1.cpp:62)
==22232== by 0x400C6C: main (20_1.cpp:127)
==22232== Address 0x5abdd28 is 8 bytes inside a block of size 16 free'd
==22232== at 0x4C2F24B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22232== by 0x400BA8: List::delete_node(int) (20
Lets take a closer look at these lines from the List::delete_node function
prev = temp;
if(temp->get_data() == data)
{
prev->set_next(temp->get_next());
delete temp;
break;
}
The first one make prev point to the very same node that temp is pointing to. After this prev == temp is true.
So when you do
prev->set_next(temp->get_next());
it is the same as
temp->set_next(temp->get_next());
That is, you make temp->next point to temp->next which doesn't change it at all. You never unlink the node from the list, but you do delete it. That makes your printing of the list invalid, as you will dereference a deleted node.
As a simple solution, you could do something like this:
if (head->get_data() == data)
{
// Special case: Head node is the one we want to delete
Node* old_head = head;
// Make the head be the second node in the list, if any
head = head->get_next();
// Delete the old head
delete old_head;
}
else
{
// We know it's not the head node of the list, use the "next" to find it
for (Node* node = head; node->get_next() != 0; node = node->get_next())
{
if (node->get_next()->get_data() == data)
{
// It's the "next" node we want to remove
Node* old_next = node->get_next();
// Unlink the node
node->set_next(node->get_next()->get_next());
delete old_next;
break;
}
}
}
The problem is that at the beginning of your do / while loop pointers temp and prev point to the same Node. Hence, you re-point the node, and then delete it right away.
A better approach is to not use prev at all. Get next, see if its data matches the one being deleted. If it does, "bypass" and delete next. Otherwise, move on to the next node until you hit NULL:
void List::delete_node(int data) {
if(head == NULL) {
return;
}
if (head->get_data() == data) {
Node *toDelete = head;
head = head->get_next();
delete toDelete;
return;
}
Node *temp = head;
for ( ; ; ) {
Node *next = temp->get_next();
if (next == null) {
break;
}
if (next->get_data() == data) {
temp->set_next(next->get_next());
delete next;
break;
}
temp = temp->get_next();
}
}
The exact working solution is
void List::delete_node(int data)
{
Node *temp = head;
Node *prev = NULL;
//first check whether its a parent element or not
if(temp && temp->get_data() == data){
head = head->get_next();
delete temp;
}
else{
while (temp){
if (temp->get_data() == data){
if (prev)
prev->set_next(temp->get_next());
delete temp;
return;
}
prev = temp;
temp = temp->get_next();
}
}
}
This even works for deleting head node
I see a number of problems with your code.
Your Node constructors is not initializing any of the Node members.
Your List class is missing a destructor to free any allocated nodes.
Your print_list() and append_node() implementations are a little more verbose than they need to be.
But, most importantly, regarding your particular question, your list's delete_node() method is not managing its prev variable correctly. prev is always pointing at the current node that is being looked at, not at the previous node that was already looked at. So you are not actually updating your links correctly when removing a node. You are also not updating the list's head member if the node being removed is the head node.
Try something more like this instead:
class Node;
class List {
Node *head;
public:
List();
~List();
void print_list();
void append_node(int data);
void delete_node(int data);
};
class Node {
int data;
Node *next;
public:
Node(int a_data = 0, Node *a_next = NULL);
void set_data(int a_data);
void set_next(Node *a_next);
int get_data();
Node* get_next();
friend class List;
};
Node::Node(int a_data, Node *a_next)
: data(a_data), next(a_next)
{
}
void Node::set_data(int a_data)
{
data = a_data;
}
void Node::set_next(Node *a_next)
{
next = a_next;
}
int Node::get_data()
{
return data;
}
Node* Node::get_next()
{
return next;
}
List::List()
: head(NULL)
{
}
List::~List()
{
Node *temp = head;
while (temp)
{
Node *next = temp->get_next();
delete temp;
temp = next;
}
}
void List::print_list()
{
Node *temp = head;
if (!temp)
{
cout << "empty" << endl;
return;
}
do
{
cout << temp->get_data();
temp = temp->get_next();
if (!temp) break;
cout << "+++>";
}
while (true);
cout << "--->NULL" << endl;
}
void List::append_node(int data)
{
Node **temp = &head;
while (*temp) temp = &((*temp)->next);
*temp = new Node(data);
}
void List::delete_node(int data)
{
Node *temp = head;
Node *prev = NULL;
while (temp)
{
if (temp->get_data() == data)
{
if (prev)
prev->set_next(temp->get_next());
if (temp == head)
head = temp->get_next();
delete temp;
return;
}
prev = temp;
temp = temp->get_next();
}
}
int main()
{
List list;
list.append_node(10);
list.append_node(20);
list.append_node(30);
list.append_node(40);
list.append_node(50);
list.append_node(60);
list.delete_node(30); //
list.print_list();
return 0;
}