Merge Sort Discussion

Moved from MergeSort.

There are a number of dubious claims being made here that are not backed up by argument nor citation.

I suggest that any further claims that are contrary to the standard literature and standard introductory textbooks should indeed be backed up by either argument or citation.

It's also a very good idea to actually try out an algorithm before making any claims about it.


MergeSort can be done in place. Let us suppose the array is divided in two sorted halves. The idea is to grab the first sorted half and make it grow at the expense of the second sorted half.

Let i and j be the pointers to the start of each half. Whenever i is incremented, the final result grows. a[i] is the first element of the first half and a[j] is the first element of the second half.

If a[i] <= a[j] then i++; else begin

  swap( a, i, j );
  insert( a, j, n ); // insert a[j] into a[j..n]
end

-- GuillermoSchwarz

Did you just make this up on the fly?

No. See SchwarzMergeSortAlgorithm?.

If not, please cite which variation this is (i.e. who published and where, etc), and what its time complexity is.

I have no idea what time complexity it has. Who cares anyway? We all know that BigOh is only the worst case scenario and the interesting scenario is the average scenario. Although I was taught how to calculate both, I recognize that doing average analysis is beyond my limited mathematical capabilities. I prefer to do real tests to back up what I'm saying. -- GuillermoSchwarz

If so, that's unwise; there are often subtle bugs in attempted new sorting algorithm variants.

I would love to see if there are any bugs in my algorithm. See SchwarzMergeSortAlgorithm?.

And the usual simple in-place merge sort costs O(n^2), making it more of a curiosity than a practical tool. At first glance, this looks like what you may be offering up here, but I don't feel like doing a deep analysis of a random algorithm.

I took the time to verify that this algorithm is faster than QuickSort, but only for big n. This is exactly the same that Knuth said when comparing QuickSort to InsertSort when n=10.

Apparently, there are moderately recent in-place mergesorts that have fairly good time complexity (although not as good as quicksort), but I was under the impression that they were far more complex than the little tweak above.

It seems evident the above tweak is sound, and remains sound if "less than" is replaced by "less than or equals" (now done), which would be sensible. I'm not sure what the typical and worst case time complexities are.

I didn't say it absolutely isn't sound, but I am saying that it's easy to end up with subtle bugs. Have you at least tried it?

Also it's essentially useless to introduce a new (or variant) sorting algorithm without knowing its time complexity. Like I said, in the absence of analysis, there is existing reason to think that such a thing would be O(n^2)

You shouldn't expect readers of this page to either trust it blindly, nor to do the analysis for you.

Actually I just looked at it a little harder, and it is (1) broken; it omits essential work, and (2) once fixed, it is indeed O(n^2). Give it a try on some worst possible case data.

As it stood, it clearly wasn't intended to be complete. It conditionally inserts the lowest element from the second half into the first half, replacing one element there which is inserted into the second half. It is sound in the sense that it preserves the order of each half and doesn't use additional storage. It also looks inefficient because of the insert process, so I wasn't motivated to establish the time complexity with certainty. Subtle bugs can arise in almost any code, even Knuth's (occasionally).

The insert process can be done fast if:

  1. The point of insertion is found fast. This means using BinarySearch.
  2. The shift is done in machine language. Most languages have a way to call the underlying machine instruction to do the shift. In Java you can use System.arraycopy, in UNIX/C you can call memmove, me thinks.

There's a reason why Knuth is so famous. :-) And for why his books are considered so useful.


About Knuth and O (BigOh) notation [Almost every top-level statement in this section is incorrect.]

According to Knuth, InsertSort is almost as bad as BubbleSort, which are O(n*n). QuickSort is much better but still O(n*n). Why is it better then? Because on average the DividePhase? is fast.

Well, on modern architectures (1999+) it turns out that Knuth was wrong, and he admitted it: InsertSort is not almost as bad as BubbleSort when you have HardwareCaches, InsertSort then performs almost as good as QuickSort

For a different opinion, see CachesDoNotAffectBigOhTimeComplexity.

because the MIX abstraction assumes that all machine instructions have constant cost.

This is not true on architectures that have paging and big and fast L1 and L2 caches: Locality is a lot more important. This explains why on modern architectures InsertSort is closer to QuickSort than to BubbleSort, while on old architectures InsertSort was closer to BubbleSort. Incorrect Why?

So you see, using O (BigOh) notation is outdated because it does not consider HardwareCaches. I don't know if Knuth, or another mathematician, has came up with a better abstraction yet. Incorrect Why?

-- GuillermoSchwarz

I found it out by myself when bored and tested the sorting algorithms. I thought I had done something wrong but couldn't find out what. And then I read that Knuth gave an interview to explain why his work did not apply any longer on modern architectures. The reason given by Knuth is that the MIX model no longer applies, because MIX assumes constant cost for all its machine instructions. This is no longer true because of the caches: If you access an array in order (for 1..n) it is faster than if you do the same randomly. BubbleSort is more random than InsertSort and it shows for large n. I can't find the link now.

P.S. BigOh/BigTheta is not outdated; each has always had, and always will have, different appropriate uses. Sometimes one is used where it shouldn't, sometimes people forget that one must look at where the curves cross, etc, etc, but this has all been known from the beginning. It's just that people aren't always careful to apply what is known.

According to Knuth, the reason MIX is so important is that if he used a high level programming language, he would have no way to know the real cost of any operation.

If MIX is broken, so are BigOh and BigTheta. Interestingly enough, most ComputerScientists apply BigOh and BigTheta to higher level languages too. The problem is that if it is broken for MIX, then it is broken for any other higher level language. What we need is a new abstraction that takes into consideration program locality. Methinks. -- GuillermoSchwarz


About InPlace? MergeSort being broken

Actually I just looked at it a little harder, and it is (1) broken; it omits essential work, and (2) once fixed, it is indeed O(n^2). Give it a try on some worst possible case data.

What's the worst possible data in this case?

-- GuillermoSchwarz

Don't know, but you might first want to take a look at the recent literature. A little web searching turns up:

Proximity Mergesort: optimal in-place sorting in the cache-oblivious model. (no direct link, but as of April 2004, available free via AcmWeb)

Practical in-place mergesort - http://thomas.baudel.name/Visualisation/VisuTri/inplacestablesort.html

That in-place MergeSort does the merge recursively. MergeSort is exactly like SillySort, but the Merge phase must be fast. I do not see how double recursion can be better than my approach that takes at between n/2 steps + n/2 * the cost of an insert. The cost of an insert is n/2 at most. If we are trying to calculate averages, n/2 increments + n/4 will be swaps + inserts (if data is random). The cost of the average insert is n/4, therefore the total cost of the merge phase is n/4 * n/4 = n^2/16. This is irrelevant, because it does not consider HardwareCaches. You can try the algorithm and see that it performs better.

-- GuillermoSchwarz


Geesh, Knuth's work will NEVER be outdated. MIX was not the standard to which Big-O applies. We are talking minimal/average costs for various operations. If you get down to the Nitty gritty of coming up with very precise Big-O's, you just about totally miss the point of Big-O. Most of the good general purpose sort algorithms are on the order of O(N*logN). This is because it has been proven that ANY sort algorithm based on key comparison must do at least N*logN comparisons. -- GeraldLindsly

Well Gerald, you'll see, I'm not claiming that inplace MergeSort is better than O(n * log n). As you say, that's impossible for a comparison-based sorting algorithm. What I'm saying is that MergeSort beats QuickSort, I'm talking in terms of averages here. Please also note that QuickSort is O(n*n) because it's worse behavior is quadratic, while at the same time HeapSort and MergeSort are O(n *log n) even for their worse behavior.

Also I don't see how you can justify your claim that Knuth will never be outdated. -- GuillermoSchwarz

Gerald is exactly correct here. -- DougMerritt


[GS, please brush up on your theory - making elementary blunders detracts from the value of your valid points.]


EditText of this page (last edited June 22, 2006) or FindPage with title or text search