Algorithms-UCSanDiego

Data Structures and Algorithms by UCSanDiego

View project on GitHub

3. Improving Quicksort

https://en.wikipedia.org/wiki/Quicksort

Problem

Solutions

CPP

    #include <iostream>
    #include <vector>
    #include <random>
    #include <sstream>
    #include <algorithm>
    #include <iterator>

    using namespace std;

    template< typename Type >
    class Solution
    {
    public:
        using Collection = vector< Type >;
        using Iter = typename Collection::iterator;
        void quickSort( Collection& A ){
            go( A, A.begin(), A.end() );
        }
    private:
        void go( Collection& A, Iter L, Iter R ){   // go() sorts from [ L : R ), that is, from L (inclusive) to R (non-inclusive)
            if( L >= R )
                return;
            iter_swap( L, random( L, R ));          // set pivot as first element
            auto[ M1, M2 ] = partition3( A, L, R );
            go( A, L, M1 );
            go( A, M2, R );
        }
        Iter partition( Collection& A, Iter L, Iter R ){
            auto threshold{ L }, less{ L+1 };
            for( auto more{ less }; more != R; ++more )
                if( *more < *threshold )
                    iter_swap( less++, more );
            auto pivot{ less-1 };
            iter_swap( L, pivot );
            return pivot;
        }
        pair< Iter, Iter > partition3( Collection& A, Iter L, Iter R ){
            auto P = partition( A, L, R ),
                 M1{ P },
                 M2{ P };
            for( auto i{ R-1 }; M2 <= i; )
                if( *i == *P )
                    iter_swap( i, M2++ );
                else
                    --i;
            return{ M1, M2 };

        }
        using RandomDevice = random_device;
        using Generator = mt19937;
        using Distribution = uniform_int_distribution< int >;
        Iter random( Iter L, Iter R, RandomDevice randomDevice=RandomDevice() ){
            Generator randomGenerator{ randomDevice() };
            int size = distance( L, R-1 );        // R-1 since R is non-inclusive
            Distribution distribution{ 0, size }; // distribution from [ 0 : size ], that is 0 ( inclusive ) to size ( inclusive )
            return L + distribution( randomGenerator );
        }
    };

    int main() {
        using Type = size_t;
        Solution< Type > solution;
        Solution< Type >::Collection A;
        auto N{ 0 }; cin >> N;
        copy_n( istream_iterator< Type >( cin ), N, back_inserter( A ));
        solution.quickSort( A );
        copy( A.begin(), A.end(), ostream_iterator< Type >( cout, " " ));
        return 0;
    }

Python3

    import random
    from typing import List

    class Solution:
        def quickSort( self, A: List[int] ):
            self.go( A, 0, len(A) )
        def go( self, A: List[int], L: int, R: int ):
            if R - L < 2:
                return
            P = random.randint( L, R-1 ) # R is non-inclusive
            A[ L ], A[ P ] = A[ P ], A[ L ]
            M1, M2 = self.partition3( A, L, R )
            self.go( A, L, M1 )
            self.go( A, M2, R )
        def partition( self, A: List[int], L: int, R: int ):
            threshold = A[ L ]
            less = L + 1
            more = less
            while more != R:
                if A[ more ] < threshold:
                    A[ less ], A[ more ] = A[ more ], A[ less ]
                    less += 1
                more += 1
            pivot = less - 1
            A[ L ], A[ pivot ] = A[ pivot ], A[ L ]
            return pivot
        def partition3( self, A: List[int], L: int, R: int ):
            P = self.partition( A, L, R )
            M1 = P
            M2 = P
            i = R - 1
            while M2 < i:
                if A[ i ] == A[ P ]:
                    A[ M2 ], A[ i ] = A[ i ], A[ M2 ]
                    M2 += 1
                else:
                    i -= 1
            return M1, M2

    if __name__ == '__main__':
        N = input()
        A = list( map( int, input().split() ))    
        Solution().quickSort( A )
        for x in A:
            print( x, end=" " )