diff --git a/base/base.pro b/base/base.pro index bfa2a40e68..8e47863b97 100644 --- a/base/base.pro +++ b/base/base.pro @@ -70,3 +70,4 @@ HEADERS += \ threaded_container.hpp \ threaded_list.hpp \ resource_pool.hpp \ + limited_priority_queue.hpp \ diff --git a/base/limited_priority_queue.hpp b/base/limited_priority_queue.hpp new file mode 100644 index 0000000000..3433dae5c9 --- /dev/null +++ b/base/limited_priority_queue.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "../base/base.hpp" +#include "../std/algorithm.hpp" +#include "../std/functional.hpp" +#include "../std/vector.hpp" + +namespace my +{ + +// Priority queue that stores only N smallest elements. +template > +class limited_priority_queue +{ +public: + typedef T value_type; + typedef typename vector::const_iterator const_iterator; + + explicit limited_priority_queue(size_t maxSize = 1, CompareT compare = CompareT()) + : m_maxSize(maxSize == 0 ? 1 : maxSize), m_compare(compare) + { + } + + void push(T const & t) + { + if (m_queue.size() < m_maxSize) + { + m_queue.push_back(t); + push_heap(m_queue.begin(), m_queue.end(), m_compare); + } + else if (m_compare(t, m_queue.back())) + { + // This can be optimized by writing decrease_head_heap(). + pop_heap(m_queue.begin(), m_queue.end(), m_compare); + m_queue.back() = t; + push_heap(m_queue.begin(), m_queue.end(), m_compare); + } + } + + void pop() + { + pop_heap(m_queue.begin(), m_queue.end(), m_compare); + m_queue.pop_back(); + } + + void set_max_size(size_t maxSize) + { + // This can be optimized by writing pop_n_heap(). + m_maxSize = (maxSize == 0 ? 1 : maxSize); + while (size() > m_maxSize) + pop(); + } + + size_t max_size() const { return m_maxSize; } + bool empty() const { return m_queue.empty(); } + size_t size() const { return m_queue.size(); } + T const & top() const { return m_queue.back(); } + + const_iterator begin() const { return m_queue.begin(); } + const_iterator end() const { return m_queue.end(); } + + void clear() { m_queue.clear(); } + + void swap(limited_priority_queue & queue) + { + m_queue.swap(queue.m_queue); + using std::swap; + swap(m_maxSize, queue.m_maxSize); + swap(m_compare, queue.m_compare); + } + +private: + vector m_queue; + size_t m_maxSize; + CompareT m_compare; +}; + +template +void swap(limited_priority_queue & q1, limited_priority_queue & q2) +{ + q1.swap(q2); +} + +} // namespace my diff --git a/std/algorithm.hpp b/std/algorithm.hpp index 803e110249..9353464c74 100644 --- a/std/algorithm.hpp +++ b/std/algorithm.hpp @@ -33,6 +33,9 @@ using std::set_difference; using std::set_symmetric_difference; using std::swap; using std::transform; +using std::push_heap; +using std::pop_heap; +using std::sort_heap; #ifdef DEBUG_NEW #define new DEBUG_NEW