简体   繁体   中英

Recursive MergeSort on a Linked List using Java

I searched on the net for a good clean and simple implentation of a merge sort algorithm in Java for a Linked List that uses recursion.

I couldn't find a nice one so Im trying to implement it here. but Im stuck.

Here is what I have so far:

public List mergeSortList(Node head, Node tail) {

    if ((head == null) || (head.next == null))
        return;

    Node middle = this.findMiddle(head);
    List left = mergeSortList(this.head, middle);
    List right = mergeSortList(middle.next, tail);
    return merge(left, right);
}

private List merge(List left, List right) {
    List returnedList = new LinkedList();

}

private Node findMiddle(Node n) {
    Node slow, fast;
    slow = fast = n;

    while (fast != null && fast.next.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}

Can someone help me correct any errors and fill the stubs please.

Thanks

First error is in following :-

while(fast != null && fast.next.next != null)
{
   slow = slow.next;
   fast = fast.next.next;
}  

fast.next can be null when you do fast.next.next , considering the case when no of elements is odd.

Here is a modified code:-

while(fast != null && fast.next.next != null)
{
    slow = slow.next;
    if(fast.next!=null)
        fast = fast.next.next;
    else break;
}  

Here is another modification:-

public List mergeSortList(Node head)
{
    if ( (head == null) || (head.next == null))
       return head;
    Node middle = this.findMiddle(head);
    Node first = head;
    Node second = middle.next;
    middle.next = null; 
    Node left = mergeSortList(first);
    Node right = mergeSortList(second);
    return merge(left, right);
 }

Explanation: You donot need to pass tail to the function, You can split the list at middle into two separate list ending with null. And after recursion of two list just reconnect them to prevent loss of original list

Here is clean and simple implementation for Merge Sort on LinkedList

public class MergeSortLinkedList {

static class Node {
    Node next;
    int value;

    Node(int value) {
        this.value = value;
    }
}

public static void main(String[] args) {
    Node head = new Node(10);
    head.next = new Node(5);
    head.next.next = new Node(2);
    head.next.next.next = new Node(1);
    head.next.next.next.next = new Node(6);
    head.next.next.next.next.next = new Node(8);
    head.next.next.next.next.next.next = new Node(3);
    head.next.next.next.next.next.next.next = new Node(2);

    print(head);

    Node sortedHead = mergeSort(head);
    print(sortedHead);
}

static void print(Node head) {
    Node tmp = head;
    while (tmp != null) {
        System.out.print(tmp.value + "->");
        tmp = tmp.next;
    }
    System.out.println();
}

static Node getMiddle(Node head) {
    if (head == null || head.next == null) {
        return head;
    }
    Node slow = head;
    Node fast = head;
    while (fast.next != null && fast.next.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

static Node sortedMerge(Node left, Node right) {
    if (left == null) {
        return right;
    }
    if (right == null) {
        return left;
    }
    if (left.value < right.value) {
        left.next = sortedMerge(left.next, right);
        return left;
    } else {
        right.next = sortedMerge(left, right.next);
        return right;
    }
}

static Node mergeSort(Node head) {
    if (head == null || head.next == null) {
        return head;
    }
    Node middle = getMiddle(head);
    Node middleNext = middle.next;
    middle.next = null;
    Node left = mergeSort(head);
    Node right = mergeSort(middleNext);
    return sortedMerge(left, right);
}

}

This looks like a good start. Your merge method is going to work just like any other merge sort implementation except you're dealing with lists instead of integers.

What you need to do is:

  • create a new list to return ('result')
  • compare the first element in List 'left' to the first in List 'right'
  • copy the smaller element to the result
  • advance your pointer into whichever list the smaller element came from
  • repeat until you hit the end of a list
  • copy all the remaining elements to the result

Take a stab at that (post your updated code) and we'll be happy to help you out more from there.

Solution divided in two methods, First method is recursive method what we call from main(), then divide list using fast and slow pointer technique (fast walks 2 step when slow walks one), now call itself recursively with both the lists, and combine returned list using second method mergeSortedList, also we are calling mergeSortedList again and again within the recursion, so at the very end when there is only one element left in each list, we compare them and add together in right order.

ListNode sortList(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode fast = head;
        ListNode slow = head;
        // get in middle of the list :
        while (fast.next!= null && fast.next.next !=null){slow = slow.next; fast = fast.next.next;}
        fast = slow.next;
        slow.next=null;
        return mergeSortedList(sortList(head),sortList(fast));
        }

ListNode mergeSortedList(ListNode firstList,ListNode secondList){
            ListNode returnNode = new ListNode(0);
            ListNode trackingPointer = returnNode;
            while(firstList!=null && secondList!=null){
                if(firstList.val < secondList.val){trackingPointer.next = firstList; firstList=firstList.next;}
                else {trackingPointer.next = secondList; secondList=secondList.next;}
                trackingPointer = trackingPointer.next;
            }
            if (firstList!=null) trackingPointer.next = firstList;
            else if (secondList!=null) trackingPointer.next = secondList;
            return returnNode.next;
            }
        }

Working solution in java. Go to the link below:

http://ideone.com/4WVYHc

import java.util.*;
import java.lang.*;
import java.io.*;

class Node
{
    int data;
    Node next;

    Node(int data){
        this.data = data;
        next = null;
    }

    void append(Node head, int val){
        Node temp = new Node(val);
        Node cur = head;

        if(head == null)
        {
            return;
        }
        while(cur.next != null)
        {
            cur = cur.next;
        }
        cur.next = temp;
        return;

    }

    void display(){

        Node cur = this;
        while(cur != null)
        {
            System.out.print(cur.data + "->");
            cur = cur.next;
        }
    }
}

class Ideone
{
    public Node findMiddle(Node head){
        if(head == null )
            return null;

        Node slow, fast;
        slow = head;
        fast = head;

        while(fast != null && fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;

    }

    public Node merge(Node first, Node second){

        Node head = null;
        while(first != null && second != null){

            if(first.data < second.data){
                if(head == null){
                    head = new Node(first.data);
                }
                else
                    head.append(head,first.data);
                first = first.next;
            }
            else if(second.data < first.data){
                    if(head == null){
                    head = new Node(second.data);
                }
                else
                    head.append(head,second.data);
                second = second.next;
            }
            else{
                    if(head == null){
                        head = new Node(first.data);
                        head.append(head,second.data);
                    }
                    else{
                        head.append(head,first.data);
                        head.append(head,second.data);
                    }
                second = second.next;
                first = first.next;
            }
        }   
            while(first != null){
                if(head == null){
                    head = new Node(first.data);
                }
                else
                    head.append(head,first.data);
                first = first.next;
            }

                while(first != null){
                if(head == null){
                    head = new Node(first.data);
                }
                else
                    head.append(head,first.data);
                first = first.next;
                }

                while(second != null){
                if(head == null){
                    head = new Node(second.data);
                }
                else
                    head.append(head,second.data);
                second = second.next;
            }


        return head;    
    }

    public Node mergeSort(Node head){

        if(head == null)
            return null;

        if(head.next == null)
            return head;

        Node first = head;
        Node mid = findMiddle(first);
        Node second = mid.next;
        mid.next = null;
        Node left = mergeSort(first);
        Node right = mergeSort(second);
        Node result = merge(left, right);
        return result;

    }

    public static void main (String[] args) throws java.lang.Exception
    {
        Node head = new Node(5);
        head.append(head,1);
        head.append(head,5);
        head.append(head,1);
        head.append(head,5);
        head.append(head,3);
        System.out.println("Unsoreted linked list:");
        head.display();
        Ideone tmp = new Ideone();
        Node result = tmp.mergeSort(head);
        System.out.println("\nSorted linked list:");
        result.display();
    }
}

Below is the Java version of the post to sort numbers in linked list using merge sort.

import java.util.ArrayList;

public class SortNumbersInLinkedListUsingMergeSort {

    Node head;

    public static void main(String[] args) {
        SortNumbersInLinkedListUsingMergeSort sll = new SortNumbersInLinkedListUsingMergeSort();
        // creating an unsorted linked list
        sll.head = new Node(2);
        sll.head.next = new Node(5);
        sll.head.next.next = new Node(3);
        sll.head.next.next.next = new Node(-1);
        sll.head.next.next.next.next = new Node(1);
        printList(sll.head);
        sll.head = Merge(sll.head);
        printList(sll.head);
    }



    // 
    public static Node Merge(Node head){

        // if linked list has no or only one element then return
        if (head == null || head.next == null){
            return null;
        }

        // split the linked list into two halves, (front and back as two heads) 
        ArrayList<Node> list = splitIntoSublists(head);

        // Recursively sort the sub linked lists 
        Merge(list.get(0));
        Merge(list.get(1));

        // merge two sorted sub lists
        head = mergeTwoSortedLists(list.get(0), list.get(1));

        return head;


    }

    // method to merge two sorted linked lists
    public static Node mergeTwoSortedLists(Node front, Node back){

        Node result;

        if (front == null){
            return back;
        }

        if (back == null){
            return front;
        }

        if (front.data >= back.data){
            result = back;
            result.next = mergeTwoSortedLists(front, back.next);
        }
        else{
            result = front;
            result.next = mergeTwoSortedLists(front.next, back);
        }

        return result;
    }

    // method to split linked list into two list in middle.
    public static ArrayList<Node> splitIntoSublists(Node head){
        Node slowPointer;
        Node fastPointer ;

        Node front = null;
        Node back = null;

        ArrayList<Node> li = new ArrayList<Node>();

        if (head == null || head.next == null){
            front = head;
            back = null;
        }
        else{
            slowPointer= head;
            fastPointer = head.next;

            while (fastPointer != null && fastPointer.next != null){

                slowPointer = slowPointer.next;
                fastPointer = fastPointer.next.next;

            }

            front = head;
            back =  slowPointer.next;
            slowPointer.next = null;

        }

        li.add(front);
        li.add(back);
        return li;
    }

    // method to print linked list
    public static void printList(Node head){
        Node pointer = head;

        while (pointer != null){
            System.out.print(pointer.data + " ");
            pointer = pointer.next;
        }
        System.out.println();
    }

}

// class to define linked list 
class Node{
    int data;
    Node next;

    public Node (int data){
        this.data = data;
    }
}

Here is a working example :

public class MergeSort{
    public Node head = null;

    public class Node {
        int val;
        Node next;

        public Node () {//Constructor
            val = 0;
            next = null;
        }
        public Node (int i) { //constructor
            val = i;
            next = null;
        }


    }
    public void insert ( int i) { //inserts node at the beginning
        Node n = new Node(i);
        n.next = head;
        head = n;
    }

    public void printList (Node head) {
        while (head != null) {
            System.out.println (head.val);
            head = head.next;
        }
    }

    public Node sort (Node head) {
        if ( head == null || head.next ==null ) return head; // no need to sort if there's no node or only one node in the Linked List
        Node mid = find_Mid (head); // find middle of the LinkedList
        Node sHalf = mid.next ; mid.next = null; //Splitting into two linked lists
        Node  h = merge ( sort(head), sort(sHalf) ); //Call merge recursively
        return h;

    }

    public Node merge ( Node n1 , Node n2) {
        Node curr = null;

        if ( n1 == null )
            return n2; //n1 empty
        if ( n2 == null )
            return n1; // n2 empty


            if ( n1.val < n2.val ) { 

                 curr=n1; 
                 curr.next = merge (n1.next, n2); //Call merge recursively

            }
            else { 

                curr = n2; 
                curr.next = merge (n1, n2.next); //Call merge recursively
            }

        return curr;

    }

    public Node find_Mid (Node head) {
        Node slow = head; Node fast = head;

        while ( fast.next != null && fast.next.next != null ) {
            slow = slow.next;
            fast = fast.next.next;
        }

        return slow;
    }

     public static void main(String []args){
        System.out.println("Hello World");
        MergeSort m = new MergeSort ();
        m.insert ( 3 );
        m.insert ( 4 );
        m.insert ( 16 );
        m.insert ( 10 );
        m.insert ( 5 );
        m.insert ( 1 );
        m.insert ( -5 );
        m.printList(m.head);
        Node n = m.find_Mid (m.head);
        System.out.println("Middle is :" + n.val);
        m.head = m.sort(m.head);
        m.printList(m.head);

     }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM