📜 ⬆️ ⬇️

Merge sort without using additional memory

I thought for a long time that it was impossible to write a merge array sorting so that it did not use additional memory, but so that the operation time remained equal to O (N * log (N)). Therefore, when karlicos shared a link to the description of such an algorithm, it interested me. A search on the network showed that people know about the algorithm, but no one is particularly interested in it, it is considered difficult and ineffective. Although, maybe, they mean some kind of “stable” version of this algorithm, but nobody still needs an unstable one.

But I still decided to try.


')

Merge in linear time



The idea of ​​the algorithm is quite simple. All we need is to merge the two ordered parts of the same array in O (N) comparisons and exchanges of elements. This is done like this:

The description is quite long, but you can understand. The number of exchanges per merger is about 5 * N , the number of comparisons is about 6 * N (it depends on the length of the remainder). For complete sorting, these numbers are multiplied by log (N) , and a lot is obtained.

Adaptation algorithm for sorting



To make it easier for us, and the algorithm worked more efficiently, we note the following.


Armed with these thoughts, we are writing a program (for now only for an array of type int []). First we sort and merge fragments with lengths equal to the power of two, and we go strictly from left to right so that there is free space to the right. When we reach the clipboard, merge the unfused, but sorted fragments. Sort the clipboard + balance, merge the result with the rest of the array, sort the newly created clipboard - and the array is sorted. It turns out the algorithm is about a hundred lines . Truth told, that he bulky. What about efficiency?

Honestly, I hoped that he would lose the standard qsort no more than 3 times. But the comparison in real conditions (on arrays up to 10 8 in length) showed that, according to the number of comparisons, the algorithm wins qsort by about 10%, and by the total operating time - from 1.2 to 1.3 times! Perhaps this is due to the fact that the icmp function (comparing two integers at given addresses) is substituted inline - but the code that is inserted turns out pretty awful (I checked).

In general, everything is not as bad as they said.

And what kind of error was in the description of the algorithm? The fact is that if an element that, after sorting, must be in one of the first R positions, got into the clipboard or the rest, it will not get into the place. To correct, you have to keep track of what place the element that was in the cell with the index R came to during the last merge, and make the initial sort of the initial fragment to this point (its length can be somewhat larger than R ).

UPD: The algorithm, as I described it here, revealed another error related to "sorting pieces of an array." If there are many identical elements in the source array, different pieces from the same fragment of the array can have the same first elements. And if the order in which these pieces go when sorting is disturbed, the result of sorting the entire array may turn out to be incorrect.

To combat this effect, when sorting, it is necessary to compare the first elements of the pieces, and if they are the same, compare the last elements. And sort the pieces lexicographically by these pairs of elements.

Source: https://habr.com/ru/post/138146/


All Articles