And here's another interesting algorithm/structure: Randomized Slide to Front

Richard Hodges via Digitalmars-d digitalmars-d at puremagic.com
Tue Dec 1 03:08:26 PST 2015


I had a little think about the pathological case of most searches 
being for one of a few elements.

I'm sure my idea is not new, but it seems to me that keeping a 
'hit count' for each element solves this. The decision of whether 
to swap then becomes:

++ Frequency[I]
if I >= Threshold1 then
   choose an index J that is [either I/2 or rand(0...I-1), 
depending on preference]
   if (Frequency[I] - Frequency[J]) >= Threshold2 then
     swap Item[I] and Item[J]
     swap Frequency[I] and Frequency[J]
     I = J
   endif
endif
return I

I wrote a little test in c++ (sorry guys, old habits die hard):

template<class T>
struct mrucache
{
     using vector_type  = std::vector<T>;
     using iterator = typename vector_type::iterator;
     using const_iterator = typename vector_type::const_iterator;

     void add(T item) {
         _items.push_back(std::move(item));
         _frequency.push_back(0);
     }

     template<class Pred>
     iterator find_if(Pred&& pred)
     {
         using std::begin;
         using std::end;
         auto iter = std::find_if(begin(_items),
                                  end(_items),
                                  std::forward<Pred>(pred));
         if (iter != end(_items))
         {
             auto i = std::distance(_items.begin(), iter);
             ++ _frequency[i];
             i = maybe_swap(i);
             iter = std::next(begin(_items), i);
         }
         return iter;
     }

     std::size_t maybe_swap(std::size_t i)
     {
         if (i >= closeness_threshold)
         {
             auto candidate_i = i / 2;
             if ((_frequency[i] - _frequency[candidate_i]) >= 
difference_threshold) {
                 swap(_items[i], _items[candidate_i]);
                 swap(_frequency[i], _frequency[candidate_i]);
                 i = candidate_i;
             }
         }
         return i;
     }

     auto begin() const { return _items.begin(); }
     auto end() const { return _items.end(); }

     static const size_t closeness_threshold = 4;
     static const int difference_threshold = 1;

     std::vector<T> _items;
     std::vector<int> _frequency;
};



More information about the Digitalmars-d mailing list