Reputation: 950
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
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