Design an efficient algorithm to sort 5 distinct keys in fewer than 8 comparisons

前端 未结 13 1305
轮回少年
轮回少年 2020-12-01 11:30

Design an efficient algorithm to sort 5 distinct - very large - keys less than 8 comparisons in the worst case. You can\'t use radix sort.

相关标签:
13条回答
  • 2020-12-01 11:33

    Sample sequence of operations, using mergesort (the merge function below will merge two sorted sublists into a single sorted combined list):

    elements[1..2] <- merge(elements[1..1], elements[2..2]) # 1 comparison
    elements[3..4] <- merge(elements[3..3], elements[4..4]) # 1 comparison
    elements[3..5] <- merge(elements[3..4], elements[5..5]) # 1-2 comparisons
    elements[1..5] <- merge(elements[1..2], elements[3..5]) # 2-4 comparisons
    
    0 讨论(0)
  • 2020-12-01 11:35

    FWIW, here's a compact and easy to follow Python version with tests to make sure it works:

    def sort5(a, b, c, d, e):
        'Sort 5 values with 7 Comparisons'
        if a < b:      a, b = b, a
        if c < d:      c, d = d, c
        if a < c:      a, b, c, d = c, d, a, b
        if e < c:
            if e < d:  pass
            else:      d, e = e, d
        else:
            if e < a:  c, d, e = e, c, d
            else:      a, c, d, e = e, a, c, d
        if b < d:
            if b < e:  return b, e, d, c, a
            else:      return e, b, d, c, a
        else:
            if b < c:  return e, d, b, c, a
            else:      return e, d, c, b, a
    
    if __name__ == '__main__':
        from itertools import permutations
    
        assert all(list(sort5(*p)) == sorted(p) for p in permutations(range(5)))
    
    0 讨论(0)
  • 2020-12-01 11:37

    I have written a C implementation of the solution to this problem which can be found here: Sorting 5 elements using 7 comparisons

    My code is well commented with an explanation of why it is working.

    0 讨论(0)
  • 2020-12-01 11:39

    Sorting networks have a restricted structure, so don't answer the original question; but they're fun.
    List of Sorting Networks generates nice diagrams or lists of SWAPs for up to 32 inputs. For 5, it gives

    There are 9 comparators in this network, grouped into 6 parallel operations.  
    [[0,1],[3,4]]  
    [[2,4]]  
    [[2,3],[1,4]]  
    [[0,3]]  
    [[0,2],[1,3]]  
    [[1,2]]
    
    0 讨论(0)
  • 2020-12-01 11:39

    Here is C++ implementation which sorts 5 elements in <= 7 comparisons. Was able to find 8 cases which can be sorted in 6 comparisons. That makes sense if we imagine full binary tree with 120 leaf nodes, there will be 112 nodes at level 7 and 8 leaf nodes at level 6. Here is the full code that is tested to work for all possible permutations.

    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <cassert>
    #include <numeric>
    
    using namespace std;
    
    ostream& operator << ( ostream& os, vector<int> v )
    {
        cout << "[ ";
        for ( auto x: v ) cout << x << ' ';
        cout << "]";
        return os;
    }
    
    class Comp {
        int count;
    public:
        Comp(): count{0}{}
        bool isLess( vector<int> v, int i, int j ) {
            count++;
            //cout << v << "Comparison#" << count << ": " << i << ", " << j << endl;
            return v[ i ] < v[ j ];
        }
        int getCount() { return count; }
    };
    
    
    int mySort( vector<int> &v )
    {
        Comp c;
        if ( c.isLess( v, 1, 0 ) ) {
            swap( v[ 0 ], v[ 1 ] );
        }
        if ( c.isLess( v, 3, 2 ) ) {
            swap( v[ 2 ], v[ 3 ] );
        }
        // By now (0, 1) (2, 3) (4)
        if ( c.isLess( v, 0, 2 ) ) {
            // ( 0, 2, 3 ) (1)
            swap( v[ 1 ], v[ 2 ] );
            swap( v[ 2 ], v[ 3 ] );
        } else {
            // ( 2, 0, 1 ) ( 3 )
            swap( v[ 1 ], v[ 2 ] );
            swap( v[ 0 ], v[ 1 ] );
        }
        // By now sorted order ( 0, 1, 2 ) ( 3 ) ( 4 ) and know that 3 > 0
        if ( c.isLess( v, 4, 1 ) ) {
            if ( c.isLess( v, 4, 0 ) ) {
                // ( 4, 0, 1, 2 ) ( 3 ) ( ... )
                v.insert( v.begin(), v[4] );
                // By now ( 0, 1, 2, 3 ) ( 4 ) ( ... ) and know that 4 > 1
                if ( c.isLess( v, 4, 2 ) ) {
                    // ( 0, 1, 4, 2, 3 ) ( ... )
                    v.insert( v.begin() + 2, v[4] );
                } else {
                    if ( c.isLess( v, 4, 3 ) ) {
                        // ( 0, 1, 2, 4, 3 ) ( ... )
                        v.insert( v.begin() + 3, v[4] );
                    } else {
                        // ( 0, 1, 2, 3, 4 ) ( ... )
                        v.insert( v.begin() + 4, v[4] );
                    }
                }
                // ( 1 2 3 4 5 ) and trim the rest
                v.erase( v.begin()+5, v.end() );
                return c.getCount(); /////////// <--- Special case we could been done in 6 comparisons
            } else {
                // ( 0, 4, 1, 2 ) ( 3 ) ( ... ) 
                v.insert( v.begin() + 1, v[4] );
            }
        } else {
            if ( c.isLess( v, 4, 2 ) ) {
                // ( 0, 1, 4, 2 ) ( 3 ) ( ... )
                v.insert( v.begin() + 2, v[4] );
            } else {
                // ( 0, 1, 2, 4 ) ( 3 ) ( ... )
                v.insert( v.begin() + 3, v[4] );
            }
        }
        // By now ( 0, 1, 2, 3 ) ( 4 )( ... ): with 4 > 0
        if ( c.isLess( v, 4, 2 ) ) {
            if ( c.isLess( v, 4, 1 ) ) {
                // ( 0, 4, 1, 2, 3 )( ... )
                v.insert( v.begin() + 1, v[4] );
            } else {
                // ( 0, 1, 4, 2, 3 )( ... )
                v.insert( v.begin() + 2, v[4] );
            }
        } else {
            if ( c.isLess( v, 4, 3 ) ) {
                // ( 0, 1, 2, 4, 3 )( ... )
                v.insert( v.begin() + 3, v[4] );
            } else {
                // ( 0, 1, 2, 3, 4 )( ... )
                v.insert( v.begin() + 4, v[4] );
            }
        }
        v.erase( v.begin()+5, v.end() );
        return c.getCount();
    }
    
    #define TEST_ALL
    //#define TEST_ONE
    
    int main()
    {
    #ifdef TEST_ALL
        vector<int> v1(5);
        iota( v1.begin(), v1.end(), 1 );
        do {
            vector<int> v2 = v1, v3 = v1;
            int count = mySort( v2 );
            if ( count == 6 )
                cout << v3 << " => " << v2 << " #" << count << endl;
        } while( next_permutation( v1.begin(), v1.end() ) );
    #endif
    
    #ifdef TEST_ONE
        vector<int> v{ 1, 2, 3, 1, 2};
        mySort( v );
        cout << v << endl;
    #endif
    }
    
    0 讨论(0)
  • 2020-12-01 11:41

    For sorting networks, it is not possible to have less than 9 comparisons to sort 5 items when the input is not known. The lower bound has been proven for sorting networks up to 10. See https://en.wikipedia.org/wiki/Sorting_network.

    Correctness of sorting networks could be verified by the Zero-one principle as mentioned in The Art of Computer Programming, Vol 3 by Knuth. That is, if a sorting network can correctly sort all permutations of 0s and 1s, then it is a correct sorting network. None of the algorithms mentioned on this post passed the Zero-one test.

    In addition, the lower bound says that comparison based sorts cannot have less than ceil(log(n!)) comparators to correctly sort, however, it does not mean that this is achievable.

    0 讨论(0)
提交回复
热议问题