2

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);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189

1 Answers1

1

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;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189