10

I am wondering what the fastest algorithm would be for this. I have 8 integers between 0 and 3000 and I need to sort them. Although there are only 8 integers, this operation will be performed millions of times.

conz
  • 121
  • 1
  • 4
  • It depends a lot on what the values are, and their initial order (and on the concrete implementation of the algorithm, the platform, ...). Ultimately you will need to measure and compare yourself. – Péter Török Jan 22 '11 at 21:19
  • 1
    How important is the `fastest` sort. With so few numbers it will make very little difference. So unless this is something hyper sensitive to speed I would start with whats the easiest way to sort 8 elements. – Martin York Jan 22 '11 at 22:10
  • If the operation will be performed millions of times, perhaps one thing to do would be to run multiple sort-8-integer operations in parallel. N cores could yield an N times speedup... – Jeremy Friesner Jun 11 '12 at 02:53
  • duplicate of [fast algorithm implementation to sort very small set](http://stackoverflow.com/q/2748749/309483) – Janus Troelsen May 12 '13 at 19:08

12 Answers12

12

Here is an implementation of an odd-even merge sort network in C99 (sorry for the "wrong" language):

#define CMP_SWAP(i, j) if (a[i] > a[j])              \
    { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; }

void sort8_network(int *a)
{
    CMP_SWAP(0, 1); CMP_SWAP(2, 3); CMP_SWAP(4, 5); CMP_SWAP(6, 7);
    CMP_SWAP(0, 2); CMP_SWAP(1, 3); CMP_SWAP(4, 6); CMP_SWAP(5, 7);
    CMP_SWAP(1, 2); CMP_SWAP(5, 6); CMP_SWAP(0, 4); CMP_SWAP(1, 5);
    CMP_SWAP(2, 6); CMP_SWAP(3, 7); CMP_SWAP(2, 4); CMP_SWAP(3, 5);
    CMP_SWAP(1, 2); CMP_SWAP(3, 4); CMP_SWAP(5, 6);
}

I timed it on my machine against insertion sort

void sort8_insertion(int *a)
{
    for (int i = 1; i < 8; i++)
    {
        int tmp = a[i];
        int j = i;
        for (; j && tmp < a[j - 1]; --j)
            a[j] = a[j - 1];
        a[j] = tmp;
    }
}

For about 10 million sorts (exactly 250 times all the 40320 possible permutations), the sort network took 0.39 seconds while insertion sort took 0.88 seconds. Seems to me both are fast enough. (The figures inlcude about 0.04 seconds for generating the permutations.)

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • Is the sorting network "optimal"? I mean, is 19 comparisons the absolute minimum needed to sort 8 elements? – dariopy Oct 09 '11 at 22:43
  • 2
    @dariopy: For a sorting network in the usual sense (i.e. code only implemented using the above `CMP_SWAP` macro), it's minimal. You could write a bunch of *nested* if statements in a way that each comparison determines which further comparisons are done, thus somehow taking into account the results of earlier comparisons. The code wouldn't use a fixed number of comparisons any more, but could make do with a maximum of 16 comparisons (an a minimum of 7). The function would get very long, though, and I doubt it would be faster. – Sven Marnach Oct 10 '11 at 16:50
7

The fastest would be to simply write a lot of if statements to compare them to determine their exact order. That will remove the overhead that any sorting algoritm has.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Exactly what I was about to suggest. – Vilx- Jan 22 '11 at 21:25
  • 1
    Actually, come to think of it... what would be the "algorithm" to get the least number of IF's? O_O – Vilx- Jan 22 '11 at 21:28
  • 4
    This is called a sorting network and I believe that optimal sorting networks are known for eight elements. – templatetypedef Jan 22 '11 at 21:33
  • Not a good solution. You would end up with a huge number of if statements. Maintenance nightmare... – Jörgen Sigvardsson Jan 22 '11 at 21:36
  • The code would look very ugly even for only 8 numbers. And if you just write an O(N^2) solution the compiler could potentially unroll it to the same set of ifs. – Martin York Jan 22 '11 at 21:57
  • 2
    This is not necessarily faster than loops. It is not uncommon that unrolling loops actually makes the code slower. – Sven Marnach Jan 22 '11 at 22:02
  • 1
    @Jörgen Sigvardsson: it's not a maintenance nightmare if you write the code to explicitly represent a known sorting network. It's also very easily testable, because you can cover the 8! = 40k significant different inputs (OK, plus a bunch more for equal values). I suppose if you set out writing a completely ad-hoc bunch of conditionals then (a) you'll rapidly get into trouble, and (b) you won't come up with anything close to optimal anyway. – Steve Jessop Jan 22 '11 at 23:17
  • 5
    @Jörgen Sigvardsson: He didn't ask for short or maintainable code, he asked what was the fastest. – Guffa Jan 22 '11 at 23:22
5

For only 8 integers and given that the range is much greater than 8, insertion sort is probably the best. Try it to start with, and if profiling indicates that it's not the bottleneck then leave it.

(Depending on many factors, the cutoff point at which quick-sort becomes better than insertion sort is usually between 5 and 10 items).

Peter Taylor
  • 4,918
  • 1
  • 34
  • 59
5

The fastest way is a sorting network implemented in hardware. Barring that, the fastest way is determined only by measuring. I'd try

  • std::sort,
  • pigeonhole (bucket) sort with reuse of the buckets,
  • a bunch of if statements, and
  • insertion sort

in that order, because it's the easiest-to-hardest order (try to get insertion sort right the first time...) until you find something that's maintainable once the constant eight turns out to have the value nine.

Also, bubble sort, selection deserve and shell sort deserve notice. I've never actually implemented those because they have bad rep, but you could try them.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • A sorting network is particularly effective if you have SIMD. – Paul R Jan 22 '11 at 21:37
  • @Paul R: I suppose so. Do MMX etc. have pairwise comparison instructions? – Fred Foo Jan 22 '11 at 21:51
  • Vertical compare (register-to-register), yes. Horizontal compare (compare high/low within register), no. – greyfade Jan 22 '11 at 22:25
  • So long as you have a reasonably large number of sets of a small number of integers which can be sorted in parallel then SIMD can give a big win using (vertical) max/min operations to implement a sorting network. A typical example might be implementing a median filter on, say, a 2D image. – Paul R Jan 23 '11 at 09:45
3

Years later) for up to 32 inputs, see the Sorting network generator. For 8 inputs, it gives 19 swaps, like Sven Marnach's answer:

o--^--^--------^--------------------------o
   |  |        |
o--v--|--^--^--|--^--^--------------------o
      |  |  |  |  |  |
o--^--v--|--v--|--|--|--^--------^--------o
   |     |     |  |  |  |        |
o--v-----v-----|--|--|--|--^--^--|--^--^--o
               |  |  |  |  |  |  |  |  |
o--^--^--------v--|--v--|--|--|--v--|--v--o
   |  |           |     |  |  |     |
o--v--|--^--^-----v-----|--|--|-----v-----o
      |  |  |           |  |  |
o--^--v--|--v-----------v--|--v-----------o
   |     |                 |
o--v-----v-----------------v--------------o


There are 19 comparators in this network,
grouped into 7 parallel operations.

[[0,1],[2,3],[4,5],[6,7]]
[[0,2],[1,3],[4,6],[5,7]]
[[1,2],[5,6],[0,4],[3,7]]
[[1,5],[2,6]]
[[1,4],[3,6]]
[[2,4],[3,5]]
[[3,4]]
denis
  • 21,378
  • 10
  • 65
  • 88
2

The following citation from Bentley et al., Engineering a sort function could be interesting here:

Various improvements to insertion sort, including binary search, loop unrolling, and handling n=2 as a special case, were not helpful. The simplest code was the fastest.

(Emphasis mine.)

This suggests that plain insertion sort without fancy modifications would indeed be a good starting point. As Peter has noted, eight items is indeed a bit tricky because that lies squarely in the range which usually marks the cut-off between insertion sort and quicksort.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
2

I ran a library of sort algorithms against all permutations of {0, 429, 857, 1286, 1714, 2143, 2571, 3000}.

The fastest were:

name                                time   stable in-place
AddressSort                         0.537   No      No
CenteredLinearInsertionSort         0.621   Yes     No
CenteredBinaryInsertionSort         0.634   Yes     No
BinaryInsertionSort                 0.639   Yes     Yes
...
QuickSort                           0.650   No      Yes
...
BubbleSort                          0.802   Yes     Yes

For more on AddressSort see http://portal.acm.org/citation.cfm?id=320834

Handcraftsman
  • 6,863
  • 2
  • 40
  • 33
0

A good source for comparing sorting algos is http://www.sorting-algorithms.com/. Note that even the initial order status affect the results. But anyway for 8 integers even a plain bubble sort should do the job.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
0

For positive integers, the fastest sort is known as abacus sort- it's O(n)

http://en.wikipedia.org/wiki/Abacus_sort

If you only have a very few items, then it's unlikely that you will notice any performance difference from choosing any particular algorithm.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 2
    A software implementation of this algorithm is O(S), where S is the sum of all integers. In the case at hand, this is a Bad Idea. – Sven Marnach Jan 22 '11 at 22:08
0

For very small numbers of ints, bubble sort can be very fast. Bubble sort with numerical comparisons can be written with a very low overhead and for small n, the actual speed differences between O(n log n) and O(n^2) washes out.

smithco
  • 679
  • 5
  • 17
0

Have you profiled your code to show that the sort is a bottleneck? If it isn't a bottleneck, then speeding it up won't buy you much. Sorting eight short integers is pretty fast.

In general, std::sort() will be faster than anything you can write, unless you are a real sorting guru.

Michael J
  • 7,631
  • 2
  • 24
  • 30
0

For integers, you could try radix-sort. It's O(N).

linello
  • 8,451
  • 18
  • 63
  • 109