views:

571

answers:

5

I know the question is not too specific.

All I want is someone to tell me how to convert a normal merge sort into an in-place merge sort (or a merge sort with constant extra space overhead).

All I can find (on the net) is pages saying "it is too complex" or "out of scope of this text".

The only known ways to merge in-place (without any extra space) are too complex to be reduced to practical program. (taken from here)

Even if it is too complex, what is the basic concept of how to make the merge sort in-place?

A: 

You can get by with constant extra space easily. Just allocate another buffer the same size as the original array and apply the merge in there:

Original buffer:

[ ................... | .....................]
  ^ sorted subarray      ^ sorted subarray

Temp buffer

[ ...........................................]
  ^ merge into this

Then you can memcpy into the original one.

This allocation happens once during initialization and can be reused at each recursion step. Each recursive call essentially has a "view" into the buffer you allocated.

Alex
@Alex: But the size of the buffer depends on the size of the input, so this algorithm does not use *constant* extra space.
Lazer
It uses constant extra space with respect to the original amount used. I guess I misinterpreted what you meant.
Alex
@Alex: It does **not** use “constant extra space with respect to the original amount used,” quite the contrary. Your interpretation is *never* the correct interpretation of “constant”. These terms are well-defined, and what you described as “constant” *depends* on the original amount of space so it cannot be “constant” (which, by definition, depends on nothing).
Konrad Rudolph
@Red-nosed, I considered it to be a extra by a constant factor. If originally the algorithm used N space, it now uses 2N, both of which are O(N).
Alex
And if the original algorithm used O(1) space it now uses O(N) space and I hope you see that this means it cannot be called “constant” extra space.
Konrad Rudolph
@Red-nosed, *wrong*. If the original algorithm used O(1) space => It used some constant C units of space, and now uses 2C units = *still* O(1). I hope you see your rudeness is unwarranted.
Alex
I think what Alex is trying to say is that the algorithm's memory usage is still O(N) even if you use 1 extra vector or 2 or 100, as long as the number of extra vectors you use is constant, and he's right about that, the memory usage is still O(N). The phrasing "constant extra space" is not the best way to put it however.
IVlad
@Alex: what rudeness? The confusion, by the way, might stem from the use of “extra” because the *original* algorithm uses no (or constant, O(1)) *extra* space (i.e. *additionally* to the input size) while yours would use O(N) extra space (again, additionally to the input size). So *here*’s the jump from O(1) to O(N) and this is why it’s not called “constant”.
Konrad Rudolph
+2  A: 

It really isn't easy or efficient, and I suggest you don't do it unless you really have to (and you probably don't have to unless this is homework since the applications of inplace merging are mostly theoretical). Can't you use quicksort instead? Quicksort will be faster anyway with a few simpler optimizations and its extra memory is O(log N).

Anyway, if you must do it then you must. Here's what I found: one and two. I'm not familiar with the inplace merge sort, but it seems like the basic idea is to use rotations to facilitate merging two arrays without using extra memory.

Note that this is slower even than the classic merge sort that's not inplace.

IVlad
Quicksort isn't stable. That *really* matters for a lot of production code.
Donal Fellows
quicksort can be stable, and iirc merge sort is not necessarily stable if in place
jk
Good links. Why did someone say, it was difficult?
+2  A: 

Including its "big result", this paper describes a couple of variants of in-place merge sort (PDF):

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.22.5514&rep=rep1&type=pdf

In-place sorting with fewer moves

Jyrki Katajainen, Tomi A. Pasanen

It is shown that an array of n elements can be sorted using O(1) extra space, O(n log n / log log n) element moves, and n log 2 n+O(n log log n) comparisons. This is the first in-place sorting algorithm requiring o(n log n) moves in the worst case while guaranteeing O(n log n) comparisons, but due to the constant factors involved the algorithm is predominantly of theoretical interest.

I think this is relevant too. I have a printout of it lying around, passed on to me by a colleague, but I haven't read it. It seems to cover basic theory, but I'm not familiar enough with the topic to judge how comprehensively:

http://comjnl.oxfordjournals.org/cgi/content/abstract/38/8/681

Optimal Stable Merging

Antonios Symvonis

This paper shows how to stably merge two sequences A and B of sizes m and n, m ≤ n, respectively, with O(m+n) assignments, O(mlog(n/m+1)) comparisons and using only a constant amount of additional space. This result matches all known lower bounds...

Steve Jessop
A: 

The critical step is getting the merge itself to be in-place. It's not as difficult as those sources make out, but you lose something when you try.

Looking at one step of the merge:

[...list-sorted...|x...list-A...|y...list-B...]

We know that the sorted sequence is less than everything else, that x is less than everything else in A, and that y is less than everything else in B. In the case where x is less than or equal to y, you just move your pointer to the start of A on one. In the case where y is less than x, you've got to shuffle y past the whole of A to sorted. That last step is what makes this expensive (except in degenerate cases).

It's generally cheaper (especially when the arrays only actually contain single words per element, e.g., a pointer to a string or structure) to trade off some space for time and have a separate temporary array that you sort back and forth between.

Donal Fellows