Showing posts with label merge-sort. Show all posts
Showing posts with label merge-sort. Show all posts

Wednesday, July 30, 2014

Union and Intersection of two unsorted Linked Lists

Problem

Given two Linked Lists, create union and intersection lists that contain union and intersection of the elements present in the given lists. Order of elments in output lists doesn’t matter.

Example

Input:
   List1: 10->15->4->20
   lsit2:  8->4->2->10
Output:
   Intersection List: 4->10
   Union List: 2->8->20->4->15->10

Solution

Method 1 - Simple
Following are simple algorithms to get union and intersection lists respectively.
Intersection (list1, list2)
Initialize result list as NULL. Traverse list1 and look for its each element in list2, if the element is present in list2, then add the element to result.
Union (list1, list2):
Initialize result list as NULL. Traverse list1 and add all of its elements to the result.
Traverse list2. If an element of list2 is already present in result then do not insert it to result, otherwise insert.
This method assumes that there are no duplicates in the given lists.
Java code:
bool isPresent (Node head, int data)
{
    Node t = head;
    while (t != NULL)
    {
        if (t.data == data)
            return true;
        t = t.next;
    }
    return false;
}   
 
 
// Function to get union of two linked lists head1 and head2 /
Node getUnion (Node head1, Node head2)
{
    Node result = NULL;
    Node t1 = head1, t2 = head2;
 
    // Insert all elements of list1 to the result list
    while (t1 != NULL)
    {
        push(&result, t1.data);
        t1 = t1.next;
    }
 
    // Insert those elements of list2 which are not present in result list
    while (t2 != NULL)
    {
        if (!isPresent(result, t2.data))
            push(&result, t2.data);
        t2 = t2.next;
    }
 
    return result;
}
 
// Function to get intersection of two linked lists head1 and head2 
Node getIntersection (Node head1, Node head2)
{
    Node result = NULL;
    Node t1 = head1;
 
    // Traverse list1 and search each element of it in list2. If the element
    // is present in list 2, then insert the element to result
    while (t1 != NULL)
    {
        if (isPresent(head2, t1.data))
            push (&result, t1.data);
        t1 = t1.next;
    }
 
    return result;
}
 
// A utility function to insert a node at the begining of a linked list/
void push (Node headRef, int newData)
{
    // allocate node /
    Node newNode = new Node();
 
    // put in the data /
    newNode.data = newData;
 
    // link the old list off the new node /
    newNode.next = (headRef);
 
    // move the head to point to the new node /
    (headRef) = newNode;
}

Time Complexity: O(mn) for both union and intersection operations.
Here m is the number of elements in first list and n is the number of elements in second list.

Method 2 - Use Merge Sort
In this method, algorithms for Union and Intersection are very similar. First we sort the given lists, then we traverse the sorted lists to get union and intersection.
Following are the steps to be followed to get union and intersection lists.
1) Sort the first Linked List using merge sort. This step takes O(mLogm) time. Refer this post for details of this step.
2) Sort the second Linked List using merge sort. This step takes O(nLogn) time. Refer this post for details of this step.
3) Linearly scan both sorted lists to get the union and intersection. This step takes O(m + n) time. This step can be implemented using the same algorithm as sorted arrays algorithm discussed here.
Time complexity of this method is O(mLogm + nLogn) which is better than method 1′s time complexity.

Method 3 (Use Hashing)
Union (list1, list2)
Initialize the result list as NULL and create an empty hash table. Traverse both lists one by one, for each element being visited, look the element in hash table. If the element is not present, then insert the element to result list. If the element is present, then ignore it.
Intersection (list1, list2)
Initialize the result list as NULL and create an empty hash table. Traverse list1. For each element being visited in list1, insert the element in hash table. Traverse list2, for each element being visited in list2, look the element in hash table. If the element is present, then insert the element to result list. If the element is not present, then ignore it.
Both of the above methods assume that there are no duplicates.
Time complexity of this method depends on the hashing technique used and the distribution of elements in input lists. In practical, this approach may turn out to be better than above 2 methods.



References

Sunday, January 19, 2014

Sort a linked list using merge sort

 Merge sort looks like a best choice for sorting the linked list.At a first appearance, merge sort may be a good  selection since the middle element is required to subdivide the given list into 2 halves, but we can easily solve this problem by moving the nodes alternatively to 2 lists.

We have discussed the sorting options for linked list here.

Merge sort is very special (in fact many standard sort libraries like in java internally uses a combination of merge sort and insertion sort) because it has the wonderful property of being a stable sort. In fact it is the only stable sort with asymptotic complexity of O(nlogn) but its draw back typically is the use of O(n) extra space. There are wonderful inline merge sort algorithms which I would cover in a different post altogether. Now what is more wonderful is that for sorting linked list, we can use merge sort’s O(nlogn) without the drawback of O(n) space. Again a quick search in net seem to suggest it is a very complicated algorithm to implement , again I am not sure why , this is my version of it (in Java).
The basic idea of merge sort is this basic recursive idea , how most of us learned recursion to start with -

merge_sort(list) {
  split list into two halfs, say first and second ;
  merge_sort(firstHalf);
  merge_sort(secondHalf);
  merge(firstHalf,secondHalf);
}

The merge algorithm on linked lists is really beautiful. The pseudocode works roughly like this:
  1. Initialize an empty linked list holding the result.
  2. As long as both lists aren't empty:
    1. If the first element of the first list is less than the first element of the second list, move it to the back of the result list.
    2. Otherwise, move the first element of the second list to the back of the result list.
  3. Now that exactly one list is empty, move all the elements from the second list to the back of the result list.
This can be made to run in O(n) time, so the overall complexity of the merge sort is O(n log n).
A working implementation in Java :
public Node merge_sort(Node head) {
    if(head == null || head.next == null) { return head; }
    Node middle = getMiddle(head);      //get the middle of the list
    Node sHalf = middle.next; middle.next = null;   //split the list into two halfs

    return merge(merge_sort(head),merge_sort(sHalf));  /recurse on that
}

public Node merge(Node a, Node b) {
    Node dummyHead, curr; dummyHead = new Node(); curr = dummyHead;
    while(a !=null && b!= null) {
        if(a.info <= b.info) { curr.next = a; a = a.next; }
        else { curr.next = b; b = b.next; }
        curr = curr.next;
    }
    curr.next = (a == null) ? b : a;
    return dummyHead.next;
}

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

Thanks

source - http://www.dontforgettothink.com/2011/11/23/merge-sort-of-linked-list/
http://stackoverflow.com/questions/7168164/sorting-linked-lists-in-c/7168300#7168300

What's the fastest algorithm for sorting a linked list?

Merge sort is the best choice. At a first appearance, merge sort may be a good  selection since the middle element is required to subdivide the given list into 2 halves, but we can easily solve this problem by moving the nodes alternatively to 2 lists.

It is reasonable to expect that you cannot do any better than O(N log N) in running time, whenever we use comparison based sorts.

However, the interesting part is to investigate if you can sort it in-place, stably, and so on.

Auxiliary storage requirement is small and constant (i.e. a few variables within the sorting routine). Thanks to the inherently different behaviour of linked lists from arrays, this Mergesort implementation avoids the O(N) auxiliary storage cost normally associated with the algorithm.

It may be possible, depending on a number of factors, it may actually be faster to copy the list to an array and then use a Quicksort.
The reason this might be faster is that an array has much better cache performance than a linked list. If the nodes in the list are dispersed in memory, you may be generating cache misses all over the place. Then again, if the array is large you will get cache misses anyway.
Mergesort parallelises better, so it may be a better choice if that is what you want. It is also much faster if you perform it directly on the linked list.
Since both algorithms run in O(n * log n), making an informed decision would involve profiling them both on the machine you would like to run them on.

 Here are some methods for sorting on linked list:
You can apply the sorting algorithms on double link list as well:

Thanks.

Bottom-up Merge Sort

Recursive algorithm
In the earlier article I’ve described a recursive version of the Merge Sort Algorithm OR Top Down Merge sort. Of course every recursive algorithm can be written in an iterative manner .

Non recursive algorithm
So today I am going to present the bottom-up version of the same algorithm, written in a non-recursive fashion .
The main idea of the bottom-up merge sort is to sort the array in a sequence of passes . During each pass the array is divided into smaller sub-arrays of a pseudo-fixed size (step or sz) . Initially step is 1, but the value increases with every pass, as every adjacent sub-arrays are merged, thus step doubles .
Top Down vs Bottom up sort

Top downBottom up
RecursiveNon recursive
It is top down, as we break the array into 2 halves, and these halves into further sub halves and so on, sort them and merge againHere we dont break into halves, rather we have a step, which determines the size of the array to be broken. Initially it is one, we sort the array of size equal to step and go further
Has more number of iterationsHas lesser number of iterations
Professor Kevin wayne (of Princeton) replied that in many cases recursion is faster than iteration because of caching improved performances.Algorithm wise it is as fast as top down, but may be slower as current implementation provide faster support for recursion

Example
0. We consider an array with size <= 1 sorted .
1. The array that needs to be sorted is A = { 5, 2, 1, 12, 2, 10, 4, 13, 5} . At this point step = 1 .
2. At the first iteration array A is divided into blocks of size step = 1 . The resulting blocks (sub-arrays) are {5}, {2}, {1}, {12}, {2}, {10}, {4}, {13}, {5} .
3. step *= 2, thus step is now 2 . At this point we have a collection of sorted sub-arrays (because their size is = 1) . We will group the sub-arrays one-by-one and we will start merging them . After the merge, the resulting sub-arrays are: {2, 5}, {1,12}, {2,10}, {4, 13} and {5} . {5} remains unpaired as the array size is an odd number . We will take care of this block later .
4. step *= 2, thus step is now 4 . Now we have a collection of 4 blocks of size two and one block of size one . We will start to merge again the adjacent blocks, so the sub-arrays collection becomes: {1, 2, 5, 12}, {2, 4, 10, 13} and {5} .
5. step *= 2, thus step is now 8 . Now we have a collection of 2 blocks with size 4 and one block with size 1 . We will merge the adjacent blocks so the sub-arrays collection becomes {1, 2, 2, 4, 5, 10, 12, 13} and {5} .
6. We now have two blocks one of size 8 and one of size 1 . We will merge those blocks and obtain the resulting sorted array: {1, 2, 2, 4, 5, 5, 10, 12, 13} .


The pseudo code for the algorithm can be written as follows . We will start by writing the merge function . This is responsible with the merging of two already sorted blocks (sub-arrays) from a given array . The input parameters for this function are : the array itself, and the interval headers (stop, start) for the two already sorted blocks . The sentinel is a concept that simplifies the code . In our case we consider SENTINEL infinity (no value from the array is bigger or equal to the Sentinel) .

Friday, August 9, 2013

Sorting


What is a sorting algorithm ?

A sorting algorithm is an algorithm that sorts the data into some order, say from ascending to descending.


The sorting problem
Input: Array of numbers , unsorted. Eg.

Output : Same numbers sorted in some order, say increasing order. Eg.

Classification of sorting algorithms
Sorting algorithm can be classified in various ways.

Comparison sorts vs non comparison sorts


Various sorts