176

This was asked of me in an interview and this is the solution I provided:

public static int[] merge(int[] a, int[] b) {

    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;
    while (i < a.length && j < b.length)
    {
        if (a[i] < b[j])
        {
            answer[k] = a[i];
            i++;
        }
        else
        {
            answer[k] = b[j];
            j++;
        }
        k++;
    }

    while (i < a.length)
    {
        answer[k] = a[i];
        i++;
        k++;
    }

    while (j < b.length)
    {
        answer[k] = b[j];
        j++;
        k++;
    }

    return answer;
}

Is there a more efficient way to do this?

Edit: Corrected length methods.

Community
  • 1
  • 1
Behrooz Karjoo
  • 4,250
  • 10
  • 38
  • 48
  • 33
    Looks like a pretty good answer to me. This problem will have O(n) complexity at best, and your answer achieves that. Anything else will be microoptimization. – Drew Hall May 11 '11 at 01:19
  • Reminds me how lazy LINQ makes you (`return a.Union(b).OrderBy(i => i);`) Perhaps with a `.ToArray()` at the end. – Matt Mitchell May 11 '11 at 01:21
  • 3
    You did good! This is essentially a part of merge sort: merging two sorted streams (from tape or disk) into another sorted stream. – Vladimir Dyuzhev May 11 '11 at 02:18
  • 14
    Have you got the job? – Shai Apr 07 '13 at 05:30
  • 5
    Also you can use ternary operator: `while (i < a.length && j < b.length) answer[k++] = a[i] < b[j] ? a[i++] : b[j++];` Java Language Specification: [Conditional Operator ? :](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25). – Anton Dozortsev Jan 27 '14 at 16:14
  • for the input int[] a = {-1,6}; int[] b = {-11,-12}; output array is coming like below {-11,-12,-1,0} – Bravo Dec 24 '14 at 10:04
  • @Bravo I checked the above code with int[] a = {-1,6}; int[] b = {-11,-12}; and it is working fine. – amitguptageek Apr 26 '16 at 15:26
  • 1
    You forgot to comment!!! – LiziPizi Apr 30 '16 at 16:07
  • 1
    Did they stipulate that there would not be any duplicates in the lists? Or that you shouldn't care about them? That's one issue I see with this code is that if the item in the first list is not less than the one in the second list, then you just take the one from the second list. So you will end up with pulling in duplicates, which may be fine for this exercise. – Kevin M Jan 04 '17 at 15:53
  • Thanks, clean code and clear logic! – Zhou Haibo Feb 07 '21 at 13:48

30 Answers30

125
public static int[] merge(int[] a, int[] b) {

    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;

    while (i < a.length && j < b.length)  
       answer[k++] = a[i] < b[j] ? a[i++] :  b[j++];

    while (i < a.length)  
        answer[k++] = a[i++];

    while (j < b.length)    
        answer[k++] = b[j++];

    return answer;
}

Is a little bit more compact but exactly the same!

Mike Saull
  • 1,415
  • 2
  • 11
  • 11
  • To the person who said this caused an index out of bounds exception what inputs are you using? It works in all cases for me. – Mike Saull Mar 25 '13 at 04:35
  • 1
    Use a for loop to merge the lines declaring the loop variables and loop control. Use double blank lines sparingly - looks uncalled for between the symmetrical "tail copies". – greybeard Feb 19 '18 at 07:13
61

I'm surprised no one has mentioned this much more cool, efficient and compact implementation:

public static int[] merge(int[] a, int[] b) {
    int[] answer = new int[a.length + b.length];
    int i = a.length - 1, j = b.length - 1, k = answer.length;

    while (k > 0)
        answer[--k] =
                (j < 0 || (i >= 0 && a[i] >= b[j])) ? a[i--] : b[j--];
    return answer;
}

Points of Interests

  1. Notice that it does same or less number of operations as any other O(n) algorithm but in literally single statement in a single while loop!
  2. If two arrays are of approximately same size then constant for O(n) is same. However if arrays are really imbalanced then versions with System.arraycopy would win because internally it can do this with single x86 assembly instruction.
  3. Notice a[i] >= b[j] instead of a[i] > b[j]. This guarantees "stability" that is defined as when elements of a and b are equal, we want elements from a before b.
Tatarize
  • 10,238
  • 4
  • 58
  • 64
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
  • This is a really really nice approach. I had trouble getting good benchmarks on my Merge sort algorithms in Swift lang. Converting this gave me what I needed, thanks very much – Chackle Jul 10 '15 at 15:54
  • What is the point of (j < 0) in the while loop? Btw, +1, This is really cool! Thanks for sharing. – Hengameh Jul 13 '15 at 03:55
  • Nice. I hope this answer will make it to the top. – Dimitar Tsonev Sep 13 '15 at 12:35
  • 2
    @Hengameh in case `j < 0`, `b` is already exhausted, so we keep adding the remaining `a` elements to the `answer` array – Natan Streppel Aug 09 '16 at 22:03
  • Thanks for pointing out! upvoted! – Muaaz salagar Nov 20 '16 at 23:18
  • But why `k > 0`? I think it should be `>=` to fill all elements in array – Michael Dec 30 '16 at 14:08
  • @Michael k is set to length of array so a s long as array is not empty, loop will execute at least once. – Shital Shah Dec 30 '16 at 22:54
  • @ShitalShah sorry, i see it already. he used prefix operator, so it will go to zero first, and then execute expression. – Michael Dec 31 '16 at 08:01
  • 12
    Too "clever" and hard to read in my mind. I prefer easier to read code especially since you aren't really achieving much of any performance improvement with this code. – Kevin M Jan 04 '17 at 15:55
  • @Kevin - yes, this might look "too clever" at first but this pattern occurs fairly often. Once you get used to it, you can just apply it out of memory. – Shital Shah Jan 04 '17 at 20:04
  • 1
    plus point for Notice, and **a[i] >= b[j] instead of a[i] > b[j]. This guarantees "stability"** – Yan Khonski Jun 16 '17 at 15:56
  • Thanks for the inspiration. Easy to generalize to merge N arrays of M length. Doesn't fit on 1 line tho. :( – Eric B. Ridge Nov 15 '17 at 00:12
  • The algorithm is slower than one suggested by Mike Saull, since you have more comparisons. Can't tell right now if it will always affect your algorithm, or for specific cases, but it will. – John Smith Mar 13 '18 at 15:45
  • @JohnSmith Boolean short circuit should take care of comparisons. Did you do any bench marking? – Shital Shah Mar 14 '18 at 02:21
  • @ShitalShah I have not done benchmarks, but just look at the code and imagine that the whole array `b` is above array `a`. Then `b` will be placed first. Then the array `a` is being placed. In your case placing array `a` requires two checks `k > 0` and `j < 0`, but the check `j<0` is not needed. once one array array is exhausted, there is no need in checking it again and again. the first code does not have this problem - if one array is exhausted only one check is performed. – John Smith Mar 14 '18 at 07:38
37

A minor improvement, but after the main loop, you could use System.arraycopy to copy the tail of either input array when you get to the end of the other. That won't change the O(n) performance characteristics of your solution, though.

Sumit Singh
  • 15,743
  • 6
  • 59
  • 89
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
18

Any improvements that could be made would be micro-optimizations, the overall algorithm is correct.

ChrisH
  • 4,788
  • 26
  • 35
  • If a is large and b is small then this algorithm is wrong. – jack Mar 20 '13 at 13:35
  • 7
    It is not wrong but not efficient. – jack Mar 20 '13 at 13:44
  • @jack how can you do it faster than O(n) when you are producing an array of n items? – Will Jun 10 '14 at 09:07
  • @will `System.arrayCopy()` is stupidly fast as it uses CPU-optimised `memcpy` calls. So there's scope to improve performance by copying chunks. There's also scope to binary search for the boundaries. – slim Jun 16 '17 at 16:16
  • Especially if you can use the sorted nature to skip most of the entries and never compare them. You can actually beat O(n). – Tatarize Feb 23 '18 at 04:35
11

This solution also very similar to other posts except that it uses System.arrayCopy to copy the remaining array elements.

private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length +b.length];
    int i =0; int j = 0;int k = 0;
    while(i<a.length && j <b.length) {
        if(a[i]<b[j]) {
            result[k++] = a[i];
            i++;
        } else {
            result[k++] = b[j];
            j++;
        }
    }
    System.arraycopy(a, i, result, k, (a.length -i));
    System.arraycopy(b, j, result, k, (b.length -j));
    return result;
}
7

Here is updated function. It removes duplicates, hopefully someone will find this usable:

public static long[] merge2SortedAndRemoveDublicates(long[] a, long[] b) {
    long[] answer = new long[a.length + b.length];
    int i = 0, j = 0, k = 0;
    long tmp;
    while (i < a.length && j < b.length) {
        tmp = a[i] < b[j] ? a[i++] : b[j++];
        for ( ; i < a.length && a[i] == tmp; i++);
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    while (i < a.length) {
        tmp = a[i++];
        for ( ; i < a.length && a[i] == tmp; i++);
        answer[k++] = tmp;
    }
    while (j < b.length) {
        tmp = b[j++];
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    return Arrays.copyOf(answer, k);
}
mkhilani
  • 9
  • 4
vitali_y
  • 400
  • 6
  • 13
6

It can be done in 4 statements as below

 int a[] = {10, 20, 30};
 int b[]= {9, 14, 11};
 int res[]=new int[a.legth+b.length]; 
 System.arraycopy(a,0, res, 0, a.length); 
 System.arraycopy(b,0,res,a.length, b.length);
 Array.sort(res)

SANN3
  • 9,459
  • 6
  • 61
  • 97
Sudhir
  • 121
  • 1
  • 1
  • 9
    I do not understand why this answer got negative votes. It is true that it is not efficient. But sometimes all you need is to get the job done as soon as possible. If you are dealing with very small arrays, say less than 100 elements, I would prefer to use the above code rather than writing a lengthy code that won't make any important performance improvements. So, thanks Sudhir for providing this easy solution and SANN3 for editing it. – Ahmadov Apr 14 '14 at 06:02
  • 2
    The unwritten premise is that a `sort` function can't use itself as a method of sorting. That would be infinite regression instead of recursion. Also the other premise is that merge_array is the function that implements sort. Thus this answer is unusable in the most likely context. – Aki Suihkonen Jul 09 '15 at 07:42
  • The question asked didn't mention that required code was for only small array. So this answer would be misleading unless it clearly stated its limitation. Also look at my answer below. It takes same number of lines to write efficient code that works for any array size :) – Shital Shah Jul 09 '15 at 07:49
  • The question stipulated that the arrays are already in sorted order. If the arrays could be very large, this solution would grind to a halt and perform poorly. So sure you'd get the required end results, but the app would not perform and you would not get the job if I were interviewing. – Kevin M Jan 04 '17 at 15:57
  • The Array.sort() function uses TimSort which very much will find the sorted runs and apply a merge sort on them. Oddly enough, this code can't really even be faulted for "not efficient" it will actually fall into finishing in O(n) time because of the sorted runs. You can run a bunch of benchmarks on it, odds are good it'll beat the OP code quite often. – Tatarize Feb 19 '18 at 00:38
  • @Ahmedov: `I do not understand why this answer got negative votes` does it answer `Is there a more efficient way to do this?` – greybeard Feb 19 '18 at 07:15
  • 1
    @greybeard - yes it does. The OP didn't specify what exactly he means by efficiency. Is it efficiency in terms of how complicated the code is, how many lines it needs to execute, or is it efficiency in terms of memory consumption, or is it efficiency based on the CPU cycles? Here, Sudhir provided a solution that is much more compact and "more efficient" if all you have a tiny Array. Remember, "premature optimization is the root of all evil". – Ahmadov Feb 19 '18 at 12:12
  • 1
    I gave the exact same answer in my interview and I think the interviewer didn’t look happy! – Mickey Donald Jan 28 '21 at 01:02
5

GallopSearch Merge: O(log(n)*log(i)) rather than O(n)

I went ahead and implemented greybeard suggestion in the comments. Mostly because I needed a highly efficient mission critical version of this code.

  • The code uses a gallopSearch which is O(log(i)) where i is the distance from the current index the relevant index exists.
  • The code uses a binarySearch for after the gallop search has identified the proper,range. Since gallop limited this to a smaller range the resulting binarySearch is also O(log(i))
  • The gallop and merge are performed backwards. This doesn't seem mission critical but it allows in place merging of arrays. If one of your arrays has enough room to store the results values, you can simply use it as the merging array and the results array. You must specify the valid range within the array in such a case.
  • It does not require memory allocation in that case (big savings in critical operations). It simply makes sure it doesn't and cannot overwrite any unprocessed values (which can only be done backwards). In fact, you use the same array for both of the inputs and the results. It will suffer no ill effects.
  • I consistently used Integer.compare() so this could be switched out for other purposes.
  • There's some chance I might have goofed a little and not utilized information I have previously proven. Such as binary searching into a range of two values, for which one value was already checked. There might also be a better way to state the main loop, the flipping c value wouldn't be needed if they were combined into two operations in sequence. Since you know you will do one then the other everytime. There's room for for some polish.

This should be the most efficient way to do this, with time complexity of O(log(n)*log(i)) rather than O(n). And worst case time complexity of O(n). If your arrays are clumpy and have long strings of values together, this will dwarf any other way to do it, otherwise it'll just be better than them.

It has two read values at the ends of the merging array and the write value within the results array. After finding out which is end value is less, it does a gallop search into that array. 1, 2, 4, 8, 16, 32, etc. When it finds the range where the the other array's read value is bigger. It binary searches into that range (cuts the range in half, search the correct half, repeat until single value). Then it array copies those values into the write position. Keeping in mind that the copy is, by necessity, moved such that it cannot overwrite the same values from the either reading array (which means the write array and read array can be the same). It then performs the same operation for the other array which is now known to be less than the new read value of the other array.

static public int gallopSearch(int current, int[] array, int v) {
    int d = 1;
    int seek = current - d;
    int prevIteration = seek;
    while (seek > 0) {
        if (Integer.compare(array[seek], v) <= 0) {
            break;
        }
        prevIteration = seek;
        d <<= 1;
        seek = current - d;
        if (seek < 0) {
            seek = 0;
        }
    }
    if (prevIteration != seek) {
        seek = binarySearch(array, seek, prevIteration, v);
        seek = seek >= 0 ? seek : ~seek;
    }
    return seek;
}

static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
    int low = fromIndex;
    int high = toIndex - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = list[mid];
        int cmp = Integer.compare(midVal, v);
        if (cmp < 0) {
            low = mid + 1;
        } else if (cmp > 0) {
            high = mid - 1;
        } else {
            return mid;// key found
        }
    }
    return -(low + 1);// key not found.
}

static public int[] sortedArrayMerge(int[] a, int[] b) {
    return sortedArrayMerge(null, a, a.length, b, b.length);
}

static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
    int write = aRead + bRead, length, gallopPos;
    if ((results == null) || (results.length < write)) {
        results = new int[write];
    }
    if (aRead > 0 && bRead > 0) {
        int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
        while (aRead > 0 && bRead > 0) {
            switch (c) {
                default:
                    gallopPos = gallopSearch(aRead, a, b[bRead-1]);
                    length = (aRead - gallopPos);
                    write -= length;
                    aRead = gallopPos;
                    System.arraycopy(a, gallopPos--, results, write, length);
                    c = -1;
                    break;
                case -1:
                    gallopPos = gallopSearch(bRead, b, a[aRead-1]);
                    length = (bRead - gallopPos);
                    write -= length;
                    bRead = gallopPos;
                    System.arraycopy(b, gallopPos--, results, write, length);
                    c = 1;
                    break;
            }
        }
    }
    if (bRead > 0) {
        if (b != results) {
            System.arraycopy(b, 0, results, 0, bRead);
        }
    } else if (aRead > 0) {
        if (a != results) {
            System.arraycopy(a, 0, results, 0, aRead);
        }
    }
    return results;
}

This should be the most efficient way to do it.


Some answers had a duplicate remove ability. That'll require an O(n) algorithm because you must actually compare each item. So here's a stand-alone for that, to be applied after the fact. You can't gallop through multiple entries all the way through if you need to look at all of them, though you could gallop through the duplicates, if you had a lot of them.

static public int removeDuplicates(int[] list, int size) {
    int write = 1;
    for (int read = 1; read < size; read++) {
        if (list[read] == list[read - 1]) {
            continue;
        }
        list[write++] = list[read];
    }
    return write;
}

Update: Previous answer, not horrible code but clearly inferior to the above.

Another needless hyper-optimization. It not only invokes arraycopy for the end bits, but also for the beginning. Processing any introductory non-overlap in O(log(n)) by a binarySearch into the data. O(log(n) + n) is O(n) and in some cases the effect will be pretty pronounced especially things like where there is no overlap between the merging arrays at all.

private static int binarySearch(int[] array, int low, int high, int v) {
    high = high - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = array[mid];
        if (midVal > v)
            low = mid + 1;
        else if (midVal < v)
            high = mid - 1;
        else
            return mid; // key found
    }
    return low;//traditionally, -(low + 1);  // key not found.
}

private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length + b.length];
    int k, i = 0, j = 0;
    if (a[0] > b[0]) {
        k = i = binarySearch(b, 0, b.length, a[0]);
        System.arraycopy(b, 0, result, 0, i);
    } else {
        k = j = binarySearch(a, 0, a.length, b[0]);
        System.arraycopy(a, 0, result, 0, j);
    }
    while (i < a.length && j < b.length) {
        result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
    }
    if (j < b.length) {
        System.arraycopy(b, j, result, k, (b.length - j));
    } else {
        System.arraycopy(a, i, result, k, (a.length - i));
    }
    return result;
}
Tatarize
  • 10,238
  • 4
  • 58
  • 64
  • 1
    Upvoted for starting to do something about the symmetry, but why stop there? Use galloping search, have it return the index *after* equal keys. Use array copy if more than 3 elements, only. Note that after that copy, nothing changed but a) the starting index in one input and the output array b) your knowledge about which "next" element is smaller. – greybeard Feb 19 '18 at 08:00
  • That is totally what the implemented Arrays.sort does. It's notably at worst a merge sort. I think they swap 2 elements where needed but fall into arraycopy for more than 2 elements. I'm unsure as to whether you'd check for the next element linearly or binary search into it. There'd be a pretty big advantage to speculatively checking if you could gallop a larger distance if you could gallop that distance. Like check 8 ahead, and if you can copy that you saved yourself 7 operations of things you don't need to look at. – Tatarize Feb 19 '18 at 22:43
  • @greybeard ... and done. Also went backwards so I could reuse the same memory. – Tatarize Feb 23 '18 at 02:51
  • Good thing you motivated going ballistic. Going to have a closer look after daytime time-sinks. – greybeard Feb 27 '18 at 09:44
  • `That is totally what the implemented Arrays.sort does` (*That*: from the first revision of your answer - or - from my Feb 19 comment?) - can't find either in Sunsoft's JDK 8: which implementation of `Arrays.sort` are you referring to? – greybeard Feb 28 '18 at 06:17
  • I looked down the source code for sort at one point and ran into the Java implementation of TimSort which seemed to do that sort of gallop merge thing. http://www.docjar.com/html/api/java/util/TimSort.java.html – Tatarize Feb 28 '18 at 07:11
  • TimSort also tends to do the merging with the galloping threshold triggered by the length of the data. Beyond just making sure the data isn't checked twice, it doesn't trigger if the data consistently is going back and forth, only when one of the merge runs is consistently long enough to invoke the gallop. – Tatarize Feb 28 '18 at 07:30
  • As is my version does seem to hit the edge condition. It checked the previous iteration, then found it failed, but then categorically can end up rechecking that value as the *low* within the binary search when it should actually check previousiteration-1 (galloping backwards) as previousiteration was explicitly checked. Though the binary search does exclusive at the high end and since I went backwards it's a bit ambiguous, and shouldn't bother the binary search if the permitted range only allows one answer. It works, but I think I have a couple possible unneeded double-checks. – Tatarize Feb 28 '18 at 07:39
4

I had to write it in javascript, here it is:

function merge(a, b) {
    var result = [];
    var ai = 0;
    var bi = 0;
    while (true) {
        if ( ai < a.length && bi < b.length) {
            if (a[ai] < b[bi]) {
                result.push(a[ai]);
                ai++;
            } else if (a[ai] > b[bi]) {
                result.push(b[bi]);
                bi++;
            } else {
                result.push(a[ai]);
                result.push(b[bi]);
                ai++;
                bi++;
            }
        } else if (ai < a.length) {
            result.push.apply(result, a.slice(ai, a.length));
            break;
        } else if (bi < b.length) {
            result.push.apply(result, b.slice(bi, b.length));
            break;
        } else {
            break;
        }
    }
    return result;
}
ebdr
  • 2,229
  • 2
  • 12
  • 8
4

Apache collections supports collate method since version 4; you can do this using the collate method in:

org.apache.commons.collections4.CollectionUtils

Here quote from javadoc:

collate(Iterable<? extends O> a, Iterable<? extends O> b, Comparator<? super O> c)

Merges two sorted Collections, a and b, into a single, sorted List such that the ordering of the elements according to Comparator c is retained.

Do not re-invent the wheel! Document reference: http://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html

Matt
  • 74,352
  • 26
  • 153
  • 180
Vlad
  • 49
  • 3
2

Here's a shortened form written in javascript:

function sort( a1, a2 ) {

    var i = 0
        , j = 0
        , l1 = a1.length
        , l2 = a2.length
        , a = [];

    while( i < l1 && j < l2 ) {

        a1[i] < a2[j] ? (a.push(a1[i]), i++) : (a.push( a2[j]), j++);
    }

    i < l1 && ( a = a.concat( a1.splice(i) ));
    j < l2 && ( a = a.concat( a2.splice(j) ));

    return a;
}
greybeard
  • 2,249
  • 8
  • 30
  • 66
swallace
  • 408
  • 1
  • 4
  • 16
1
    public class Merge {

    // stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
    public static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {

        // precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
        assert isSorted(a, lo, mid);
        assert isSorted(a, mid+1, hi);

        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k]; 
        }

        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)              a[k] = aux[j++];
            else if (j > hi)               a[k] = aux[i++];
            else if (less(aux[j], aux[i])) a[k] = aux[j++];
            else                           a[k] = aux[i++];
        }

        // postcondition: a[lo .. hi] is sorted
        assert isSorted(a, lo, hi);
    }

    // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, aux, lo, mid);
        sort(a, aux, mid + 1, hi);
        merge(a, aux, lo, mid, hi);
    }

    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length-1);
        assert isSorted(a);
    }


   /***********************************************************************
    *  Helper sorting functions
    ***********************************************************************/

    // is v < w ?
    private static boolean less(Comparable v, Comparable w) {
        return (v.compareTo(w) < 0);
    }

    // exchange a[i] and a[j]
    private static void exch(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }


   /***********************************************************************
    *  Check if array is sorted - useful for debugging
    ***********************************************************************/
    private static boolean isSorted(Comparable[] a) {
        return isSorted(a, 0, a.length - 1);
    }

    private static boolean isSorted(Comparable[] a, int lo, int hi) {
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[i-1])) return false;
        return true;
    }


   /***********************************************************************
    *  Index mergesort
    ***********************************************************************/
    // stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
    private static void merge(Comparable[] a, int[] index, int[] aux, int lo, int mid, int hi) {

        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = index[k]; 
        }

        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)                    index[k] = aux[j++];
            else if (j > hi)                     index[k] = aux[i++];
            else if (less(a[aux[j]], a[aux[i]])) index[k] = aux[j++];
            else                                 index[k] = aux[i++];
        }
    }

    // return a permutation that gives the elements in a[] in ascending order
    // do not change the original array a[]
    public static int[] indexSort(Comparable[] a) {
        int N = a.length;
        int[] index = new int[N];
        for (int i = 0; i < N; i++)
            index[i] = i;

        int[] aux = new int[N];
        sort(a, index, aux, 0, N-1);
        return index;
    }

    // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static void sort(Comparable[] a, int[] index, int[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, index, aux, lo, mid);
        sort(a, index, aux, mid + 1, hi);
        merge(a, index, aux, lo, mid, hi);
    }

    // print array to standard output
    private static void show(Comparable[] a) {
        for (int i = 0; i < a.length; i++) {
            StdOut.println(a[i]);
        }
    }

    // Read strings from standard input, sort them, and print.
    public static void main(String[] args) {
        String[] a = StdIn.readStrings();
        Merge.sort(a);
        show(a);
    }
}
jackhao
  • 3,457
  • 3
  • 22
  • 43
1

I think introducing the skip list for the larger sorted array can reduce the number of comparisons and can speed up the process of copying into the third array. This can be good if the array is too huge.

sriragav
  • 11
  • 1
1
public int[] merge(int[] a, int[] b) {
    int[] result = new int[a.length + b.length];
    int aIndex, bIndex = 0;

    for (int i = 0; i < result.length; i++) {
        if (aIndex < a.length && bIndex < b.length) {
            if (a[aIndex] < b[bIndex]) {
                result[i] = a[aIndex];
                aIndex++;
            } else {
                result[i] = b[bIndex];
                bIndex++;
            }
        } else if (aIndex < a.length) {
            result[i] = a[aIndex];
            aIndex++;
        } else {
            result[i] = b[bIndex];
            bIndex++;
        }
    }

    return result;
}
Andrew
  • 21
  • 1
1
public static int[] merge(int[] a, int[] b) {
    int[] mergedArray = new int[(a.length + b.length)];
    int i = 0, j = 0;
    int mergedArrayIndex = 0;
    for (; i < a.length || j < b.length;) {
        if (i < a.length && j < b.length) {
            if (a[i] < b[j]) {
                mergedArray[mergedArrayIndex] = a[i];
                i++;
            } else {
                mergedArray[mergedArrayIndex] = b[j];
                j++;
            }
        } else if (i < a.length) {
            mergedArray[mergedArrayIndex] = a[i];
            i++;
        } else if (j < b.length) {
            mergedArray[mergedArrayIndex] = b[j];
            j++;
        }
        mergedArrayIndex++;
    }
    return mergedArray;
}
Etienne Lawlor
  • 6,817
  • 18
  • 77
  • 89
  • What is the saving grace of this? It can be shrunk to `for (int i, j, k = i = j = 0 ; k < c.length ; ) c[k++] = b.length <= j || i < a.length && a[i] < b[j] ? a[i++] : b[j++];`. How does it differ from [Andrew's 2014 answer](https://stackoverflow.com/a/24195323/3789665)? – greybeard Feb 19 '18 at 07:42
1

Algorithm could be enhanced in many ways. For instance, it is reasonable to check, if a[m-1]<b[0] or b[n-1]<a[0]. In any of those cases, there is no need to do more comparisons. Algorithm could just copy source arrays in the resulting one in the right order.

More complicated enhancements may include searching for interleaving parts and run merge algorithm for them only. It could save up much time, when sizes of merged arrays differ in scores of times.

Hengameh
  • 892
  • 7
  • 12
  • For this enhancement it would be better to check where the first element would fall in the second array with a binarysearch, then arraycopy that data to begin. Then in the case that one of those checks is true, it would just have arraycopy everything then arraycopy the ternary and you get the same result. But, in the case of a tiny bit of overlap, you only need to do the proper algorithm during the overlap and no other time. Since you're stuck with O(n) using some quick O(logn) command beforehand isn't going to cost anything. – Tatarize Feb 18 '18 at 23:19
1

This problem is related to the mergesort algorithm, in which two sorted sub-arrays are combined into a single sorted sub-array. The CLRS book gives an example of the algorithm and cleans up the need for checking if the end has been reached by adding a sentinel value (something that compares and "greater than any other value") to the end of each array.

I wrote this in Python, but it should translate nicely to Java too:

def func(a, b):
    class sentinel(object):
        def __lt__(*_):
            return False

    ax, bx, c = a[:] + [sentinel()], b[:] + [sentinel()], []
    i, j = 0, 0

    for k in range(len(a) + len(b)):
        if ax[i] < bx[j]:
            c.append(ax[i])
            i += 1
        else:
            c.append(bx[j])
            j += 1

    return c
d11wtq
  • 34,788
  • 19
  • 120
  • 195
1

You could use 2 threads to fill the resulting array, one from front, one from back.

This can work without any synchronization in the case of numbers, e.g. if each thread inserts half of the values.

tkruse
  • 10,222
  • 7
  • 53
  • 80
0
//How to merge two sorted arrays into a sorted array without duplicates?
//simple C Coding
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
    int InputArray1[] ={1,4,5,7,8,9,12,13,14,17,40};
    int InputArray2[] ={4,5,11,14,15,17,18,19,112,122,122,122,122};
    int n=10;
    int OutputArray[30];
    int i=0,j=0,k=0;
    //k=OutputArray
    while(i<11 && j<13)
    {
        if(InputArray1[i]<InputArray2[j])
        {
            if (k == 0 || InputArray1[i]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray1[i];
            }
            i=i+1;
        }
        else if(InputArray1[i]>InputArray2[j])
        {
            if (k == 0 || InputArray2[j]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray2[j];
            }
            j=j+1;
        }
        else
        {
            if (k == 0 || InputArray1[i]!= OutputArray[k-1])
            {
                OutputArray[k++] = InputArray1[i];
            }
            i=i+1;
            j=j+1;
        }
    };
    while(i<11)
    {
        if(InputArray1[i]!= OutputArray[k-1])
            OutputArray[k++] = InputArray1[i++];
        else
            i++;
    }
    while(j<13)
    {
        if(InputArray2[j]!= OutputArray[k-1])
            OutputArray[k++] = InputArray2[j++];
        else
            j++;
    }
    for(i=0; i<k; i++)
    {
        printf("sorted data:%d\n",OutputArray[i]);
    };
}
Chanchal
  • 17
  • 1
0
var arrCombo = function(arr1, arr2){
  return arr1.concat(arr2).sort(function(x, y) {
    return x - y;
  });
};
Alex Hawkins
  • 616
  • 7
  • 10
  • 2
    This answer does not apply to the Java programming language, though it would be a good answer for javascript. – gknicker Feb 09 '15 at 06:20
  • This was part a job interview. In these cases, you're not really expected to write "normal" code like above. They're looking for "efficient" code and a demonstration that you understand the algorithms involved. – d11wtq Sep 25 '15 at 05:33
0

My favorite programming language is JavaScript

function mergeSortedArrays(a, b){
    var result = [];

    var sI = 0;
    var lI = 0;
    var smallArr;
    var largeArr;
    var temp;

    if(typeof b[0] === 'undefined' || a[0]<b[0]){
        smallArr = a;
        largeArr = b;
    } else{
        smallArr = b;
        largeArr = a;
    }

    while(typeof smallArr[sI] !== 'undefined'){
        result.push(smallArr[sI]);
        sI++;

        if(smallArr[sI]>largeArr[lI] || typeof smallArr[sI] === 'undefined'){
            temp = smallArr;
            smallArr = largeArr;
            largeArr = temp;
            temp = sI;
            sI = lI;
            lI = temp;
        }
    }
    return result;
}
Saad Ahmed
  • 1,077
  • 9
  • 9
0

Maybe use System.arraycopy

public static byte[] merge(byte[] first, byte[] second){
    int len = first.length + second.length;
    byte[] full = new byte[len];
    System.arraycopy(first, 0, full, 0, first.length);
    System.arraycopy(second, 0, full, first.length, second.length);
    return full;
}
nurisezgin
  • 1,530
  • 12
  • 19
0
public static void main(String[] args) {
    int[] arr1 = {2,4,6,8,10,999};
    int[] arr2 = {1,3,5,9,100,1001};

    int[] arr3 = new int[arr1.length + arr2.length];

    int temp = 0;

    for (int i = 0; i < (arr3.length); i++) {
        if(temp == arr2.length){
            arr3[i] = arr1[i-temp];
        }
        else if (((i-temp)<(arr1.length)) && (arr1[i-temp] < arr2[temp])){
                arr3[i] = arr1[i-temp];
        }
        else{
            arr3[i] = arr2[temp];
            temp++;
        }
    }

    for (int i : arr3) {
        System.out.print(i + ", ");
    }
}

Output is :

1, 2, 3, 4, 5, 6, 8, 9, 10, 100, 999, 1001,

Rajesh Gurbani
  • 211
  • 1
  • 6
  • 18
0

You can use ternary operators for making the code a bit more compact

public static int[] mergeArrays(int[] a1, int[] a2) {
    int[] res = new int[a1.length + a2.length];
    int i = 0, j = 0;

    while (i < a1.length && j < a2.length) {
        res[i + j] = a1[i] < a2[j] ? a1[i++] : a2[j++];
    }

    while (i < a1.length) {
        res[i + j] = a1[i++];
    }

    while (j < a2.length) {
        res[i + j] = a2[j++];
    }

    return res;
}
Jenna Kwon
  • 1,212
  • 1
  • 12
  • 22
0
public static int[] mergeSorted(int[] left, int[] right) {
    System.out.println("merging " + Arrays.toString(left) + " and " + Arrays.toString(right));
    int[] merged = new int[left.length + right.length];
    int nextIndexLeft = 0;
    int nextIndexRight = 0;
    for (int i = 0; i < merged.length; i++) {
        if (nextIndexLeft >= left.length) {
            System.arraycopy(right, nextIndexRight, merged, i, right.length - nextIndexRight);
            break;
        }
        if (nextIndexRight >= right.length) {
            System.arraycopy(left, nextIndexLeft, merged, i, left.length - nextIndexLeft);
            break;
        }
        if (left[nextIndexLeft] <= right[nextIndexRight]) {
            merged[i] = left[nextIndexLeft];
            nextIndexLeft++;
            continue;
        }
        if (left[nextIndexLeft] > right[nextIndexRight]) {
            merged[i] = right[nextIndexRight];
            nextIndexRight++;
            continue;
        }
    }
    System.out.println("merged : " + Arrays.toString(merged));
    return merged;
}

Just a small different from the original solution

Ranga
  • 1,191
  • 12
  • 19
0

To marge two sorted array in O(m+n) time complexity use below approach with one loop only. m and n is length of first array and second array.

public class MargeSortedArray {
    public static void main(String[] args) {
        int[] array = new int[]{1,3,4,7};
        int[] array2 = new int[]{2,5,6,8,12,45};
        int[] newarry = margeToSortedArray(array, array2);
        //newarray is marged array
    }

    // marge two sorted array with o(a+n) time complexity
    public static int[] margeToSortedArray(int[] array, int[] array2) {
        int newarrlen = array.length+array2.length;
        int[] newarr = new int[newarrlen];

        int pos1=0,pos2=0;
        int len1=array.length, len2=array2.length;

        for(int i =0;i<newarrlen;i++) {     
            if(pos1>=len1) {
                newarr[i]=array2[pos2];
                pos2++;
                continue;
            }
            if(pos2>=len2) {
                newarr[i]=array[pos1];
                pos1++;
                continue;
            }

            if(array[pos1]>array2[pos2]) {
                newarr[i]=array2[pos2];
                pos2++;
            } else {
                newarr[i]=array[pos1];
                pos1++;
            }   
        }

        return newarr;
    }

}
Birbal Singh
  • 1,062
  • 7
  • 16
0
var arr1 = [2,10,20,30,100];
var arr2 = [2,4,5,6,7,8,9];
var j = 0;
var i =0;
var newArray = [];

for(var x=0;x< (arr1.length + arr2.length);x++){
    if(arr1[i] >= arr2[j]){                //check if element arr2 is equal and less than arr1 element
        newArray.push(arr2[j]);
      j++;
    }else if(arr1[i] < arr2[j]){            //check if element arr1 index value  is less than arr2 element
        newArray.push(arr1[i]);
        i++;
    }
    else if(i == arr1.length || j < arr2.length){    // add remaining arr2 element
        newArray.push(arr2[j]);
        j++
    }else{                                                   // add remaining arr1 element
        newArray.push(arr1[i]); 
        i++
    }

}

console.log(newArray);
Amar1990
  • 11
  • 4
-1

Since the question doesn't assume any specific language. Here is the solution in Python. Assuming the arrays are already sorted.

Approach 1 - using numpy arrays: import numpy

arr1 = numpy.asarray([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 11, 14, 15, 55])
arr2 = numpy.asarray([11, 32, 43, 45, 66, 76, 88])

array = numpy.concatenate((arr1,arr2), axis=0)
array.sort()

Approach 2 - Using list, assuming lists are sorted.

list_new = list1.extend(list2)
list_new.sort()
Joe
  • 15,205
  • 8
  • 49
  • 56
  • 1
    `Since the question doesn't assume any specific language` from 2011/5/11/19:43, it is tagged [tag:java]. – greybeard Feb 19 '18 at 08:06
  • your solution does not take advantage of the fact lists are already sorted, and its runtime is not O(n), since `.sort()` is `O(n log n)` at best – dark_ruby Aug 29 '18 at 19:25
-1

Here is my java implementation that remove duplicate.

public static int[] mergesort(int[] a, int[] b) {
    int[] c = new int[a.length + b.length];
    int i = 0, j = 0, k = 0, duplicateCount = 0;

    while (i < a.length || j < b.length) {
        if (i < a.length && j < b.length) {
            if (a[i] == b[j]) {
                c[k] = a[i];
                i++;j++;duplicateCount++;
            } else {
                c[k] = a[i] < b[j] ? a[i++] : b[j++];
            }
        } else if (i < a.length) {
            c[k] = a[i++];
        } else if (j < a.length) {
            c[k] = b[j++];
        }
        k++;
    }

    return Arrays.copyOf(c, c.length - duplicateCount);
}
kdebugging
  • 317
  • 1
  • 2
  • 11
-2
import java.util.Arrays;

public class MergeTwoArrays {

    static int[] arr1=new int[]{1,3,4,5,7,7,9,11,13,15,17,19};
    static int[] arr2=new int[]{2,4,6,8,10,12,14,14,16,18,20,22};

    public static void main(String[] args){
        int FirstArrayLocation =0 ;
        int SecondArrayLocation=0;
        int[] mergeArr=new int[arr1.length + arr2.length];

        for ( int i=0; i<= arr1.length + arr2.length; i++){
            if (( FirstArrayLocation < arr1.length ) && (SecondArrayLocation < arr2.length)){
                if ( arr1[FirstArrayLocation] <= arr2[SecondArrayLocation]){
                    mergeArr[i]=arr1[FirstArrayLocation];
                    FirstArrayLocation++;
                }else{
                    mergeArr[i]=arr2[SecondArrayLocation];
                    SecondArrayLocation++;
                }
            }
            else if(SecondArrayLocation < arr2.length){
                    mergeArr[i]=arr2[SecondArrayLocation];
                    SecondArrayLocation++;
            }else if ( FirstArrayLocation < arr1.length ){
                    mergeArr[i]=arr1[FirstArrayLocation];
                    FirstArrayLocation++;
            }
        }
    }
}
Andrea
  • 11,801
  • 17
  • 65
  • 72