namespace hito {
namespace detail {
template < typename Iterator >
void merge_sort( Iterator first, Iterator last
                , typename std::iterator_traits<Iterator>::difference_type const n
                , typename std::iterator_traits<Iterator>::value_type * buf )
{
    if (n < 4)
    {
        for ( ; first != last ; ++first)
        {
            Iterator iter = std::min_element(first, last) ;
            if (iter != first)
            std::iter_swap(first, iter) ;
        }
        return ;
    }
    Iterator mid(first) ;
    std::advance(mid, n / 2) ;
    
    merge_sort(first, mid, n / 2, buf) ;
    merge_sort(mid, last, n / 2, buf) ;
    std::copy(first, mid, buf) ;
    typename std::iterator_traits<Iterator>::value_type * const end(buf + n / 2) ;
    while ( buf != end && mid != last )
    {
        if ( *buf < *mid )
        {
            *first = *buf ;
            ++buf ;
        }
        else
        {
            *first = *mid ;
            ++mid ;
        }
        ++first ;
    }
    std::copy(buf, end, first) ;
}
} // namespace detail
template < typename Iterator >
void merge_sort( Iterator first, Iterator last )
{
    typename std::iterator_traits<Iterator>::difference_type n = std::distance(first, last) ;
    if ( n == 1 )
        return ; // Done
    typedef typename std::iterator_traits<Iterator>::value_type type ;
    type * buf = new type[(n + 1) / 2] ;
    detail::merge_sort(first, last, n, buf) ;
    delete[] buf ;
}
} // namespace hito
 結局、どう実装するのが一番最適なのだろう。これはBidirectinalIteratorでもソート可能だ。しかし、RandomAccessIteratorの場合は、引数のnなどいらない。ランダムアクセスイテレータに対して、std::distanceはフリーだからだ。実際どうするべきなんだろう。
 そしてふと、Nicolai JosuttisのSTL本を紐解くと、驚くべき事実が載っていた。stable_sortのイテレータはRandomAccessIteratorである。そんな馬鹿な。VC8のDinkumwareはBidirectionalIteratorでもソート可能だ。これは一体どういうことだ。規格を読むと、25.3.1.2に、確かにRandomAccessIteratorとある。しかし、実際にBidirectionalなlistのイテレータを渡しても、ソートできる(listはもっといいメンバ関数があるのだが) ヘルプや、Dinkumwareのソースでは、双方向イテレータになっている。ふーむ。VCの独自仕様なのだろう。実際、マージソートは、双方向イテレータでも、それほど問題はないと思われる。
この前のチャットは失礼しました。
ReplyDeletestd::stable_sortがRandomAccessIteratorなのは、メモリが十分に無い時にソートアルゴリズムを切り替えるのと何か関係があるんでしょうかね。