Merge sort on linked lists - c++

I was trying a merge sort on linked lists.
I was keeping my head variable global and applied the basic algorithm i.e. divide and conquer.
I am not understanding why I am getting a segmentation fault.
I know I could do it by passing head as a reference, but i still need to know why this is happening.
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node *next;
};
Node *head;
void push(Node **head_ref, int x) {
Node *temp = new Node();
temp->next = *head_ref;
temp->data = x;
*head_ref = temp;
}
void split(Node *temp, Node **a, Node **b) {
Node *slow;
Node *fast;
slow = temp;
fast = temp->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
*a = temp;
*b = slow->next;
slow->next = NULL;
}
Node *mergesort(Node *a, Node *b) {
if (a == NULL) {
return b;
} else
if (b == NULL) {
return a;
}
if (a->data < b->data) {
a->next = mergesort(a->next, b);
return a;
} else {
b->next = mergesort(a, b->next);
return b;
}
}
void merge(Node **head_ref) {
Node *head = *(head_ref);
Node *a;
Node *b;
if (head == NULL || head->next == NULL) {
return;
}
split(head, &a, &b);
merge(&a);
merge(&b);
head = mergesort(a, b);
}
void print(Node *n) {
while (n != NULL) {
cout << n->data << " ";
n = n->next;
}
}
My Main method is below:
int main() {
Node *head;
push(&head, 1);
push(&head, 3);
push(&head, 6);
push(&head, 4);
push(&head, 2);
print(head);
merge(&head);
cout << endl;
print(head);
}

There are a few simple bugs in your code:
head is defined as a global variable, but also as a local variable in main, so this local variable is used inside main and not the global one. There is indeed no need for a global variable.
The local variable Node *head; in main() is not initialized. All the push calls will succeed, constructing a list pointed to by head but with an undefined pointer for the next node after 1, print will crash trying to dereference this pointer. The behavior is undefined, you might habe a null pointer by chance in head but you might might instead have an invalid pointer, causing undefined behavior. Initialize head to NULL:
Node *head = NULL;
at the end of merge, you do not update the head pointer through head_ref, so the variable in the callers is not updated. Write this:
*head_ref = mergesort(a, b);
Note that it would be simpler for merge to receive a Node *head pointer and return the updated Node * head pointer.
Note also that your function names are confusing: merge should be named mergesort and vice-versa.
Here is a modified version:
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node *next;
};
void push(Node **head_ref, int x) {
Node *temp = new Node();
if (temp) {
temp->next = *head_ref;
temp->data = x;
*head_ref = temp;
}
}
void split(Node *temp, Node **a, Node **b) {
Node *slow = temp;
Node *fast = temp->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
*a = temp;
*b = slow->next;
slow->next = NULL;
}
Node *merge(Node *a, Node *b) {
if (a == NULL) {
return b;
}
if (b == NULL) {
return a;
}
if (a->data <= b->data) {
a->next = merge(a->next, b);
return a;
} else {
b->next = merge(a, b->next);
return b;
}
}
Node *mergesort(Node *head) {
Node *a;
Node *b;
if (head == NULL || head->next == NULL) {
return head;
}
split(head, &a, &b);
a = mergesort(a);
b = mergesort(b);
return merge(a, b);
}
void print(const Node *n) {
while (n != NULL) {
cout << n->data << " ";
n = n->next;
}
count << endl;
}
int main() {
Node *head = NULL;
push(&head, 1);
push(&head, 3);
push(&head, 6);
push(&head, 4);
push(&head, 2);
print(head);
head = mergesort(head);
print(head);
return 0;
}

Related

Merge sort a Linked list (segementation fault)

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

merge sort implementation with linked list

I am trying to implement merge sort in a linked list in c++. When I execute my code, it runs infinitely no. of time. When I debug it, I found that my mergesort function runs only for the left half infinite number no. of times.I mean it never comes out from left half. That function never called for the right half. I am pasting my whole code link here. Can anyone tell me why the function runs infinitely and what modifications I have to make to my code?
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
#define mod 1000000007
struct Node {
int data;
struct Node* link;
};
Node* head = NULL;
void ins(int data, int pos)
{
Node* ptr = new Node();
ptr->data = data;
ptr->link = NULL;
if (pos == 1) {
ptr->link = head;
head = ptr;
return;
}
Node* temp = new Node();
temp = head;
for (int i = 1; i < pos - 1; i++) {
temp = temp->link;
}
ptr->link = temp->link;
temp->link = ptr;
return;
}
Node* getmid(Node* temp)
{
if (temp == 0) {
return temp;
}
Node* a = temp;
Node* b = temp;
while (b->link != 0) {
b = b->link;
a = a->link;
if (b->link != 0) {
b = b->link;
}
else {
break;
}
}
return a;
}
Node* merge(Node* left, Node* right)
{
Node* res = NULL;
if (left == NULL || right == NULL) {
if (left == NULL) {
return right;
}
if (right == NULL) {
return left;
}
else {
return NULL;
}
}
else if ((left->data) < (right->data)) {
res = left;
res->link = merge(left->link, right);
}
else {
res = right;
res->link = merge(left, right->link);
}
return res;
}
Node* mergesort(Node* head)
{
if (head == NULL || (head->link) == NULL) {
return head;
}
Node* mid = getmid(head);
Node* left = head;
Node* right = mid->link;
mid->link = NULL;
left = mergesort(left);
right = mergesort(right);
Node* c = merge(left, right);
return c;
}
void display()
{
Node* t = head;
while (t != 0) {
cout << t->data << " ";
t = t->link;
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
ins(8, 1);
ins(23, 2);
ins(73, 3);
ins(4, 4);
ins(5, 5);
ins(7, 6);
mergesort(head);
display();
}
In the above code, ins function is used to insert the node. getmid function is used for getting the address of the middle node. merge function is used to sort the left and right half. And mergesort function is used to divide the list into 2 half and call each half.display function is used for print linked list
Maybe this can help you.
#include <bits/stdc++.h>
using namespace std;
/* Link list node */
class Node {
public:
int data;
Node* next;
};
/* function prototypes */
Node* SortedMerge(Node* a, Node* b);
void FrontBackSplit(Node* source,
Node** frontRef, Node** backRef);
/* sorts the linked list by changing next pointers (not data) */
void MergeSort(Node** headRef)
{
Node* head = *headRef;
Node* a;
Node* b;
/* Base case -- length 0 or 1 */
if ((head == NULL) || (head->next == NULL)) {
return;
}
/* Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);
/* Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);
/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}
/* See https:// www.geeksforgeeks.org/?p=3622 for details of this
function */
Node* SortedMerge(Node* a, Node* b)
{
Node* result = NULL;
/* Base cases */
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
/* Pick either a or b, and recur */
if (a->data <= b->data) {
result = a;
result->next = SortedMerge(a->next, b);
}
else {
result = b;
result->next = SortedMerge(a, b->next);
}
return (result);
}
/* UTILITY FUNCTIONS */
/* Split the nodes of the given list into front and back halves,
and return the two lists using the reference parameters.
If the length is odd, the extra node should go in the front list.
Uses the fast/slow pointer strategy. */
void FrontBackSplit(Node* source,
Node** frontRef, Node** backRef)
{
Node* fast;
Node* slow;
slow = source;
fast = source->next;
/* Advance 'fast' two nodes, and advance 'slow' one node */
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
/* 'slow' is before the midpoint in the list, so split it in two
at that point. */
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
/* Function to print nodes in a given linked list */
void printList(Node* node)
{
while (node != NULL) {
cout << node->data << " ";
node = node->next;
}
}
/* Function to insert a node at the beginging of the linked list */
void push(Node** head_ref, int new_data)
{
/* allocate node */
Node* new_node = new Node();
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* Driver program to test above functions*/
int main()
{
/* Start with the empty list */
Node* res = NULL;
Node* a = NULL;
/* Let us create a unsorted linked lists to test the functions
Created lists shall be a: 2->3->20->5->10->15 */
push(&a, 15);
push(&a, 10);
push(&a, 5);
push(&a, 20);
push(&a, 3);
push(&a, 2);
/* Sort the above created Linked List */
MergeSort(&a);
cout << "Sorted Linked List is: \n";
printList(a);
return 0;
}
The issue was in getmid()
For lists of 2 elements it returned the second element, instead of the first.
Therefore with 2 elements left always pointed to the whole list, causing an infinite recursion.
Node* getmid(Node* temp)
{
if (temp == nullptr)
return nullptr;
if (temp->link == nullptr)
return temp;
Node* a = temp;
//---------------------------------
Node* b = temp->link; // Here!
//---------------------------------
while (b->link != nullptr) {
b = b->link;
a = a->link;
if (b->link != nullptr)
b = b->link;
else
break;
}
return a;
}
You can run it here: https://onlinegdb.com/3fhqQyBhy
I'm using nullptr instead of NULL or 0 and I'm passing the list as a parameter to the insert function

Why am I getting a segmentation fault when I try to run mergesort on my C++ linked list? (SEGFAULT)

I am implementing a linked list with a merge sort function for a class project. My program compiles, but when I try to run it I get segmentation fault(core dumped). I debugged my program using GDB, and found that the segfault happens with the pointer frontRef and backRef in my listSplit() function (line 98 in the code below).
Can someone please help me? For the life of me I can't figure out why I am getting a segfault. I would greatly appreciate help with this.
#include "orderedList.h"
orderedList::orderedList() {
listLength = 0;
traversalCount = 0;
head = nullptr;
tail = nullptr;
}
void orderedList::add(int n) {
listLength++;
struct node* point = new node;
point->value = n;
point->next = nullptr;
if (head == nullptr) {
head = point;
tail = point;
}
else {
point->next = head;
head = point;
}
}
void orderedList::merge(struct node** headRef) {
struct node *listHead = *headRef;
struct node *a;
struct node *b;
if ((listHead == nullptr) || (listHead->next == nullptr)) {
return;
}
listSplit(listHead, &a, &b);
merge(&a);
merge(&b);
*headRef = sortedMerge(a, b);
}
orderedList::node* orderedList::sortedMerge(struct node* a, struct node *b)
{
struct node* result = nullptr;
if (a == nullptr) {
return (b);
}
if (b == nullptr) {
return (a);
}
if (a->value <= b->value) {
result = a;
result->next = sortedMerge(a->next, b);
}
else {
result = b;
result->next = sortedMerge(a, b->next);
}
return (result);
}
void orderedList::print() {
struct node* temp = head;
while (temp != nullptr) {
std::cout << temp->value << " ";
temp = temp->next;
}
delete(temp);
}
int orderedList::search(int key) {
int traversals = 1;
struct node* current = head;
struct node* previous = nullptr;
while (current != nullptr) {
if (current->value == key) {
if (previous != nullptr) {
previous->next = current->next;
current->next = head;
head = current;
return traversals;
}
}
previous = current;
current = current->next;
traversals ++;
}
return 1;
}
void orderedList::listSplit(struct node* source, struct node** frontRef, struct node** backRef) { // <--- Line 98
struct node* current = source;
int hopCount = ((listLength - 1) / 2);
for (int i = 0; i < hopCount; i++) {
current = current->next;
}
*frontRef = source;
*backRef = current->next;
current->next = nullptr;
}
You made *backRef point to current->next and then you let current->next = nullptr. This makes *backRef pointing to a nullptr. Did you later try to do something with the returned backRef, aka a node variable in your caller code?

Merge Sort Singly Linked List in C++ failing for large input

Update. its working for 65,519 in the FOR LOOP. If i increase it to 65,520, it fails. Completely strange.
This program is not working for large inputs. It is perfect for small inputs. I am getting an exception on Xcode.
Thread 1 : EXC_BAD_ACCESS (code=2, address = 0x7fff5f3fffb8).
Kindly let me know how I can bypass this strange error.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct Node * nodePtr;
struct Node{
int data;
nodePtr next;
};
nodePtr globalHead;
void partition(nodePtr head, nodePtr *front, nodePtr *back){
nodePtr fast;
nodePtr slow;
if (head == NULL || head->next == NULL){
*front = head; // &a
*back = NULL; // &b
}else{
slow = head;
fast = head->next;
while(fast != NULL){
fast = fast->next;
if(fast != NULL){
slow = slow->next;
fast = fast->next;
}
}
*front = head; // a
*back = slow->next; // b
slow->next = NULL;
//printList(*front);
//printList(*back);
}
}
nodePtr mergeLists(nodePtr a, nodePtr b){
nodePtr mergedList = NULL;
if (a == NULL){
return b;
}else if (b == NULL){
return a;
}
try {
if (a->data <= b->data){
mergedList = a;
mergedList->next = mergeLists(a->next, b);
}else{
mergedList = b;
mergedList->next = mergeLists(a, b->next);
}
}
catch (int e) {
cout << "Error is . . " << e << endl;
}
return mergedList;
}
void mergeSort(nodePtr *source){
nodePtr head = *source;
nodePtr a = NULL;
nodePtr b = NULL;
if(head == NULL || head->next == NULL){
return;
}
partition(head, &a, &b);
mergeSort(&a);
mergeSort(&b);
*source = mergeLists(a, b);
}
void push(nodePtr *head, int data){
nodePtr newNode = (nodePtr) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if ((*head) == NULL){
*head = newNode;
globalHead = *head;
}else{
(*head)->next = newNode;
*head = newNode;
}
}
void printList(nodePtr head){
nodePtr current = head;
while(current != NULL){
printf("%d ",current->data);
current = current->next;
}
printf("\n");
}
// *head = head in the main function,
// it is only there to connect the two and
// not let make the function return anything
// passed by reference
// globalHead points to the start of the linked list
// if you are passing the address over here you have to
// make a double pointer over there in the function
int main(void)
{
nodePtr head = NULL;
// linked list is formed from top to bottom fashion
// push is done in constant time O(1)
long long int i;
//Pushing 200,000 Elements to the Linked List.
for(i=1 ; i<=200000 ; i++) {
push(&head, rand()%200000);
}
printList(globalHead);
mergeSort(&globalHead);
cout << "After Sorting . . \n";
printList(globalHead);
return 0;
}
Using recursion mergeLists() is the issue, it will call itself for every node on the list. Try changing the code so that the code loops and appends nodes to the initially empty mergeList, using a second pointer to node, or optionally a pointer to pointer to node which is initially set to &mergeList. For example, using the name pMerge instead of mergeList:
Node * mergeLists(Node *a, Node *b)
{
Node *pMerge = NULL; // ptr to merged list
Node **ppMerge = &pMerge; // ptr to pMerge or prev->next
if(a == NULL)
return b;
if(b == NULL)
return a;
while(1){
if(a->data <= b->data){ // if a <= b
*ppMerge = a;
a = *(ppMerge = &(a->next));
if(a == NULL){
*ppMerge = b;
break;
}
} else { // b <= a
*ppMerge = b;
b = *(ppMerge = &(b->next));
if(b == NULL){
*ppMerge = a;
break;
}
}
}
return pMerge;
}
Here is example code of a fast method to sort a linked list using an array of pointers to lists aList[], where aList[i] points to a list of size 2 to the power i, that makes use of mergeLists().
#define NUMLISTS 32 // size of aList
Node * mergeSort(NODE *pList)
{
Node * aList[NUMLISTS]; // array of pointers to lists
Node * pNode;
Node * pNext;
int i;
if(pList == NULL) // check for empty list
return NULL;
for(i = 0; i < NUMLISTS; i++) // zero array
aList[i] = NULL;
pNode = pList; // merge nodes into array
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = mergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS)
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; // merge array into one list
for(i = 0; i < NUMLISTS; i++)
pNode = mergeLists(aList[i], pNode);
return pNode;
}

After exiting from function, nodes aren't saved

My program should create a linked list and show it. My problem is when the addelemnt_end function ends, it doesn't update head and last.
I tried with debug and when my function is done, the info and next part from head and last are "unable to read memory".
struct node{
int info;
node *next;
};
node *head, *last;
void addelement_end(node *head, node *last, int element)
{if (head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
last = temp;
head = temp;
}
else {node*temp = new node;
last->next = temp;
temp->info = element;
temp->next = NULL;
last = temp;
}
}
void show(node* head, node *last)
{
if (head==NULL)
cout << "Empty list";
else
while (head != NULL)
{
cout << head->info << " ";
head = head->next;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int x, n, i;
cout << "how many numbers";
cin >> n;
head = last = NULL;
for (i =1; i <= n; i++)
{
cin >> x;
addelement_end(head, last, x);
}
show(head, last);
return 0;
}
It's a very common error. Here is a similar illustration of the problem:
int change_a(int a) {
a = 42;
}
int main() {
int a = 10;
change_a(a);
printf("%d\n", a);
return 0;
}
This will print 10 because in the function change_a you are only modifying a copy of the value contained in the variable a.
The correct solution is passing a pointer (or using a reference since you are using C++).
int change_a(int *a) {
*a = 42;
}
int main() {
int a = 10;
change_a(&a);
printf("%d\n", a);
return 0;
}
But maybe you're going to tell me: "I'm already using a pointer!". Yes, but a pointer is just a variable. If you want to change where the pointer points, you need to pass a pointer to that pointer.
So, try this:
void addelement_end(node **head, node **last, int element)
{
if (*head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
*last = temp;
*head = temp;
}
else {
node *temp = new node;
(*last)->next = temp;
temp->info = element;
temp->next = NULL;
*last = temp;
}
}