Scarl
Scarl

Reputation: 950

Merge sort on a linked list

So I've been trying to sort a linked list using merge sort, I found this code and tried to work on it, but it doesn't seen to really work?

What could be the problem with it? I'm not quite sure about the getMiddle method although I know it should get the middle value of the list in order to work on 2 lists from the list itself

Here's the code;

public Node mergeSort(Node head) {

    if (head == null || head.link == null) {
        return head;       
    }

    Node middle = getMiddle(head);

    Node sHalf = middle.link;
    middle.link = null;       

    return merge(mergeSort(head), mergeSort(sHalf));
}

public Node merge(Node a, Node b) {
    Node dummyHead;
    Node current;

    dummyHead = new Node();
    current = dummyHead;

    while (a != null && b != null) {
        if ((int) a.getData() <= (int) b.getData()) {
            current.link = a;
            a.link = a;
        }
        else {
            current.link = b;
            b.link = a;
        }
        current = current.link;
    }
    current.link = (a == null) ? b : a;
    return dummyHead;
}

public Node getMiddle(Node head) {
    if (head == null) {
        return head;
    }
    Node slow, fast;
    slow = fast = head;
    while (fast.link != null && fast.link.link != null) {
        slow = slow.link;
        fast = fast.link.link;
    }
    return slow;
}

In the main method:

  Object data;
    MyLinkedList list = new MyLinkedList();         //empty list.


    for (int i = 0; i < 3; i++) {           //filling the list
        data = console.nextInt();
        list.insertAtFront(data);
    }


    System.out.print("Print(1): ");
    list.printList();

   list.mergeSort(list.getHead());
    System.out.print("List after sorting: ");
    list.printList();

Upvotes: 0

Views: 443

Answers (1)

asaini007
asaini007

Reputation: 836

One problem is the getMiddle method doesn't correctly return the middle Node.

Consider a linked list with 5 Nodes (a, b, c, d, e)

head, slow, and fast all begin at index 0 (a).

After the first iteration of the while loop, slow is at 1 (b) and fast is at 2 (c); after the second iteration, slow is at 2 (c) and fast at 4 (e). These are both not null, so another iteration happens, putting slow at at 3 (d) and fast at null. Since fast is null, the while loop is exited and slow is returned; however slow has node 3 (d) rather than the middle node, 2 (c).

An alternate way to get the middle node would be to simply use the number of nodes:

public Node getMiddle(Node head) {
    Node counter = head;
    int numNodes = 0;
    while(counter != null) {
        counter = counter.link;
        numNodes++;
    }
    if(numNodes == 0)
        return null;
    Node middle = head;
    for(int i=0; i<numNodes/2; i++)
        middle = middle.link;
    return middle;
}

I your mergeSort method is fine, but technically it only needs to return head if head.link is null, not if head itself is null (since that would never happen anyhow):

public Node mergeSort(Node head) {
    if (head.link == null) {
        return head;       
    }
    // same
}

Most importantly, your merge method. You can write a public void setData(Object) method in your Node class to make this easier. The following code should work, although I can't claim it's the best/most efficient way to do the job

public Node merge(Node a, Node b) {
    Node combined = new Node();
    Node current = combined;
    while(a != null || b != null) {
        if(a == null)
            addNode(current, b);
        if(b == null)
            addNode(current, a);
        if((int)a.getData()<(int)b.getData())
            addNode(current, a);
        else
            addNode(current, b);
    }
    return combined;
}

Uses the following helper method:

public void addNode(Node n1, Node n2) {
    n1.setData((int)n2.getData());
    n1.link = new Node();
    n1 = n1.link;
    n2 = n2.link
}

Upvotes: 1

Related Questions