41

I need some help with my CS homework. I need to write a sorting routine that sorts an array of length 5 using 7 comparisons in the worst case (I've proven that 7 will be needed, because of the height of the decision tree).

I considered using the decision tree 'hard-coded', but that means the algorithm is really complicated and was hinted by my tutor that's not the way it's supposed to be done.

I've checked quicksort, merge sort, heap sort, d-ary heap sort, insertion sort, selection sort, all do not answer the requirement, which leads me to believe there's a need for a specific algorithm for arrays of length 5.

Would really like to get some hints towards the right direction.

5
  • 10
    There is an easier way to prove that at least 7 comparisons are needed. There are (5!) = 120 permutations of 5 elements, and (2 ** 7) = 128 different outcomes for 7 comparisons.
    – Mark Byers
    Commented Dec 20, 2009 at 8:19
  • 9
    +1, for a well-phrased question that states the problem clearly, shows what you have done so far, and - most importantly - mentions this is homework.
    – MAK
    Commented Dec 20, 2009 at 19:34
  • 2
    drdobbs.com/sorting-networks/184402663 seems to state 9 comparisons are needed... maybe cause it's old? Commented May 12, 2013 at 17:07
  • see also: Fastest sort of fixed length 6 int array Commented May 14, 2013 at 1:10
  • 1
    Sequence A036604 at the Online Encyclopedia of Integer Sequences shows that 7 is the minimum number of comparisons needed to sort 5 elements. (Link noted in this answer.) Commented Mar 26, 2019 at 19:40

6 Answers 6

25

Donald Knuth's The Art of Computer Programming, volume 3 has a section on exactly this topic. I don't have the books here with me, but I'm pretty sure Knuth presents the algorithm for 5 elements. As you suspect, there isn't a general algorithm that gives the minimal number of comparisons for many sizes, but there are a number of common tricks that are used in such algorithms.

From vague recollections, I reconstructed the algorithm for 5 elements, and it can be done in 7 comparisons. First, take two separate pairs, compare inside those, and compare the smaller ones of each pair. Then, compare the remaining one against the larger of these. This now splits into two cases according to whether the remaining element was smaller or larger, but in all cases it's possible to finish in the three comparisons still available.

I recommend drawing pictures to help you. Knuth's pictures are something like this:

   o---o
  /
 o---o

which shows the results after the first three comparisons (and from what I recall, this kind of a picture appears in many minimal-comparison sorts). A line connects two elements whose order we know. Having such pictures helps you in determining which elements to compare against, as you want to make a comparison that gives you the maximal amount of information.

Addendum: Since there is an accepted answer with actual code, I guess there's no harm in finishing up these diagrams, and they might be a useful addition to the answer. So, start with the above one, and compare the missing element against the one on the top left. If it is larger, this will lead to

    /--o
   o
  / \--o
 o
  \--o

Now, compare the two large elements at the top right and we end up with

   o---o---o
  /
 o---o

Now, by comparing the bottom right element first against the middle one on top and then against whichever side it belongs on, we place it correctly using the remaining two comparisons.

If the initial comparison resulted in the remaining element being smaller, the diagram becomes

 o---o---o
    /
   o---o

Now, compare the two that have yet nothing smaller than them. One option is the last diagram above, which is solvable with the remaining two comparisons. The other case is

       o---o
      /
 o---o---o

And here again, the one that is not yet in sequence with the others can be placed correctly with two comparisons.

2
14

Yes it is in Knuth vol 3 page 185 (section 5.3.1). This was first documented in a PhD thesis so your Prof is being quite hard on you! There is no really simple elegant method; you have to track it as a partially ordered tree.

Here it is in lisp. Tested OK (SBCL on Linux)

(defun small-sort (a)  
  "Sort a vector A of length 5"  
  (if (> (aref a 0) (aref a 1))  
      (rotatef (aref a 0) (aref a 1)))  
  (if (> (aref a 2) (aref a 3))  
      (rotatef (aref a 2) (aref a 3)))  
  (if (> (aref a 0) (aref a 2))  
      (progn  
        (rotatef (aref a 0) (aref a 2))  
        (rotatef (aref a 1) (aref a 3))))  
  (if (> (aref a 4) (aref a 2))  
      (if (> (aref a 4) (aref a 3))  
          (progn)  
          (rotatef (aref a 3) (aref a 4)))  
      (if (> (aref a 4) (aref a 0))  
          (rotatef (aref a 2) (aref a 4) (aref a 3))  
          (rotatef (aref a 0) (aref a 4) (aref a 3) (aref a 2))))  
  (if (> (aref a 1) (aref a 3))  
      (if (> (aref a 1) (aref a 4))  
          (rotatef (aref a 1) (aref a 2) (aref a 3) (aref a 4))  
          (rotatef (aref a 1) (aref a 2) (aref a 3)))  
      (if (> (aref a 1) (aref a 2))  
          (rotatef (aref a 1) (aref a 2))  
          (progn)))  
  a)  

(defun check-sorted (a)  
  (do ((i 0 (1+ i)))  
      ((>= i (1- (array-dimension a 0))))  
    ;;(format t "~S ~S~%" (aref a i) (aref a (+ 1 i)))  
    (assert (<= (aref a i) (aref a (+ 1 i))))))  

(defun rr ()  
  (dotimes (i 100000)  
    (let ((a (make-array 5 :initial-contents (list (random 1.0) (random 1.0) (random 1.0) (random 1.0) (random 1.0) ))))  
      ;;(format t "A=~S~%" a)  
      (let ((res (small-sort a)))  
        (check-sorted res)  
        ;;(format t "Res=~S~%" res)  
        ))))  
5
  • 4
    It's not THAT hard... the same question was passed to me in my algorithms class.
    – Chip Uni
    Commented Dec 20, 2009 at 18:18
  • 1
    can you generate the sorting function for a given array length? Commented May 12, 2013 at 16:21
  • 1
    I reimplemented the Ford-Johnson algorithm in C++ as described by Knuth, as well as your specific function for 5 elements. Sorting every permutation of [0, 1, 2, 3, 4] with this algorithms takes 840 comparisons while it only takes 832 comparisons with the Ford-Johnson algorithm. I fear that your implementation is close but not exactly the same as the one described by Knuth.
    – Morwenn
    Commented Jan 9, 2016 at 23:49
  • it's not that hard and rare, my prof threw this to me as a multiple-choice question in a 10-minute tests with 2 questions. Commented Sep 10, 2021 at 6:56
  • 1
    @Morwenn, Indeed it seems the following 8 sequences should only require 6 comparisons; all others require 7. When ascending: [0, 3, 1, 2, 4], [0, 3, 2, 1, 4], [1, 2, 0, 3, 4], [1, 2, 3, 0, 4], [2, 1, 0, 3, 4], [2, 1, 3, 0, 4], [3, 0, 1, 2, 4], [3, 0, 2, 1, 4] When descending: [1, 4, 2, 3, 0], [1, 4, 3, 2, 0], [2, 3, 1, 4, 0], [2, 3, 4, 1, 0], [3, 2, 1, 4, 0], [3, 2, 4, 1, 0], [4, 1, 2, 3, 0], [4, 1, 3, 2, 0] 5! * 7 = 340 - 8 = 832 Commented Dec 7, 2022 at 2:49
0

Take a look at bucket sort.

5
  • 3
    Bucket sort is not a comparison sort, so although it does satisfy that fewer than 7 comparisons are needed, I doubt that it is going to be accepted as a correct answer to his homework.
    – Mark Byers
    Commented Dec 20, 2009 at 8:09
  • 1
    Well yea, its not a comparison sort, but where does the requirements say that it must be a comparison sort.
    – monksy
    Commented Dec 20, 2009 at 8:22
  • 2
    He says he needs to find an algorithm "using 7 comparisons in worst case". Bucket sort doesn't satisfy that.
    – Mark Byers
    Commented Dec 20, 2009 at 8:31
  • 1
    You can still count the comparisons of bucket sort. It never said that it had to be by a comparison sort algorithm.
    – monksy
    Commented Dec 20, 2009 at 8:47
  • 2
    Hmm, I'm not sure I can use non-comparison sorts, but any way, given that the elements in the array can be anything, it is possible that all elements will fall in the same bucket (hash collision) and so the next sort will be one of the ones mentioned above that take too long...
    – CS n00b
    Commented Dec 20, 2009 at 9:10
0

7 sounds like it could be shell sort as well.

1
  • 2
    Hmm, just implemented it and it required 8 comparisons for 5,4,3,2,1
    – CS n00b
    Commented Dec 20, 2009 at 8:53
0

I don't think the hard-coded solution needs to be all that complicated:

  1. Compare (elements) 2 & 3, and swap if needed
  2. Compare 3 & 4, and swap if required
  3. Compare 1 & 3, if 1 is less, then compare 1 & 2, otherwise compare 1 & 4. Place 1 in the correct slot.
  4. Repeat step 3 except with elements 3 & 5.

That will always use 7 comparisons.

EDIT:

I don't think this is going to work: Step 4 is broken, and might require an 8th comparison. Consider:

Index | 1 | 2 | 3 | 4 | 5 |
Value | 2 | 3 | 4 | 5 | 1 |

Step 4:

  1. Compare 3 & 5 == 4 vs 1 == element 5 less than element 3
  2. Compare 2 & 5 == 3 vs 1 == element 5 less than element 2
  3. ??? Need to compare 1 & 5 to know where to put element 5.
1
  • How do you know if 1 is less or more than 5?
    – Mark Byers
    Commented Dec 20, 2009 at 9:00
0

Bucket sort can be implemented as a comparison algorithm as follows:

Take an element.

Compare it to all buckets.

Drop it into the bucket that matches. <- Comparison needed.

If bucket not found, create a new bucket.

Therefore it's a dynamic bucket sort algorithm which I just described.

I already invented/described this on newsgroup in the past.

2
  • This is not a comparison sort and does not use fewer comparisons when the input does not contain duplicates.
    – Navin
    Commented Sep 3, 2021 at 23:22
  • compare it to all bucks .... doesn't need a comparison? Commented Sep 10, 2021 at 6:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.