// // boost heap: d-ary heap as containter adaptor // // Copyright (C) 2010 Tim Blechmann // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_HEAP_D_ARY_HEAP_HPP #define BOOST_HEAP_D_ARY_HEAP_HPP #include #include #include #include #include #include #include #include #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif #ifndef BOOST_DOXYGEN_INVOKED #ifdef BOOST_HEAP_SANITYCHECKS #define BOOST_HEAP_ASSERT BOOST_ASSERT #else #define BOOST_HEAP_ASSERT(expression) #endif #endif namespace boost { namespace heap { namespace detail { struct nop_index_updater { template static void run(T &, std::size_t) {} }; typedef parameter::parameters, boost::parameter::optional, boost::parameter::optional, boost::parameter::optional, boost::parameter::optional, boost::parameter::optional > d_ary_heap_signature; /* base class for d-ary heap */ template class d_ary_heap: private make_heap_base::type { typedef make_heap_base heap_base_maker; typedef typename heap_base_maker::type super_t; typedef typename super_t::internal_type internal_type; typedef typename heap_base_maker::allocator_argument::template rebind::other internal_type_allocator; typedef std::vector container_type; typedef typename container_type::const_iterator container_iterator; typedef IndexUpdater index_updater; container_type q_; static const unsigned int D = parameter::binding::type::value; template friend struct heap_merge_emulate; struct implementation_defined: extract_allocator_types { typedef T value_type; typedef typename detail::extract_allocator_types::size_type size_type; typedef typename heap_base_maker::compare_argument value_compare; typedef typename heap_base_maker::allocator_argument allocator_type; struct ordered_iterator_dispatcher { static size_type max_index(const d_ary_heap * heap) { return heap->q_.size() - 1; } static bool is_leaf(const d_ary_heap * heap, size_type index) { return !heap->not_leaf(index); } static std::pair get_child_nodes(const d_ary_heap * heap, size_type index) { BOOST_HEAP_ASSERT(!is_leaf(heap, index)); return std::make_pair(d_ary_heap::first_child_index(index), heap->last_child_index(index)); } static internal_type const & get_internal_value(const d_ary_heap * heap, size_type index) { return heap->q_[index]; } static value_type const & get_value(internal_type const & arg) { return super_t::get_value(arg); } }; typedef detail::ordered_adaptor_iterator ordered_iterator; typedef detail::stable_heap_iterator iterator; typedef iterator const_iterator; typedef void * handle_type; }; typedef typename implementation_defined::ordered_iterator_dispatcher ordered_iterator_dispatcher; public: typedef T value_type; typedef typename implementation_defined::size_type size_type; typedef typename implementation_defined::difference_type difference_type; typedef typename implementation_defined::value_compare value_compare; typedef typename implementation_defined::allocator_type allocator_type; typedef typename implementation_defined::reference reference; typedef typename implementation_defined::const_reference const_reference; typedef typename implementation_defined::pointer pointer; typedef typename implementation_defined::const_pointer const_pointer; typedef typename implementation_defined::iterator iterator; typedef typename implementation_defined::const_iterator const_iterator; typedef typename implementation_defined::ordered_iterator ordered_iterator; typedef typename implementation_defined::handle_type handle_type; static const bool is_stable = extract_stable::value; explicit d_ary_heap(value_compare const & cmp = value_compare()): super_t(cmp) {} d_ary_heap(d_ary_heap const & rhs): super_t(rhs), q_(rhs.q_) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES d_ary_heap(d_ary_heap && rhs): super_t(std::move(rhs)), q_(std::move(rhs.q_)) {} d_ary_heap & operator=(d_ary_heap && rhs) { super_t::operator=(std::move(rhs)); q_ = std::move(rhs.q_); return *this; } #endif d_ary_heap & operator=(d_ary_heap const & rhs) { static_cast(*this) = static_cast(rhs); q_ = rhs.q_; return *this; } bool empty(void) const { return q_.empty(); } size_type size(void) const { return q_.size(); } size_type max_size(void) const { return q_.max_size(); } void clear(void) { q_.clear(); } allocator_type get_allocator(void) const { return q_.get_allocator(); } value_type const & top(void) const { BOOST_ASSERT(!empty()); return super_t::get_value(q_.front()); } void push(value_type const & v) { q_.push_back(super_t::make_node(v)); reset_index(size() - 1, size() - 1); siftup(q_.size() - 1); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template void emplace(Args&&... args) { q_.emplace_back(super_t::make_node(std::forward(args)...)); reset_index(size() - 1, size() - 1); siftup(q_.size() - 1); } #endif void pop(void) { BOOST_ASSERT(!empty()); std::swap(q_.front(), q_.back()); q_.pop_back(); if (q_.empty()) return; reset_index(0, 0); siftdown(0); } void swap(d_ary_heap & rhs) { super_t::swap(rhs); q_.swap(rhs.q_); } iterator begin(void) const { return iterator(q_.begin()); } iterator end(void) const { return iterator(q_.end()); } ordered_iterator ordered_begin(void) const { return ordered_iterator(0, this, super_t::get_internal_cmp()); } ordered_iterator ordered_end(void) const { return ordered_iterator(size(), this, super_t::get_internal_cmp()); } void reserve (size_type element_count) { q_.reserve(element_count); } value_compare const & value_comp(void) const { return super_t::value_comp(); } private: void reset_index(size_type index, size_type new_index) { BOOST_HEAP_ASSERT(index < q_.size()); index_updater::run(q_[index], new_index); } void siftdown(size_type index) { while (not_leaf(index)) { size_type max_child_index = top_child_index(index); if (!super_t::operator()(q_[max_child_index], q_[index])) { reset_index(index, max_child_index); reset_index(max_child_index, index); std::swap(q_[max_child_index], q_[index]); index = max_child_index; } else return; } } /* returns new index */ void siftup(size_type index) { while (index != 0) { size_type parent = parent_index(index); if (super_t::operator()(q_[parent], q_[index])) { reset_index(index, parent); reset_index(parent, index); std::swap(q_[parent], q_[index]); index = parent; } else return; } } bool not_leaf(size_type index) const { const size_t first_child = first_child_index(index); return first_child < q_.size(); } size_type top_child_index(size_type index) const { // invariant: index is not a leaf, so the iterator range is not empty const size_t first_index = first_child_index(index); typedef typename container_type::const_iterator container_iterator; const container_iterator first_child = q_.begin() + first_index; const container_iterator end = q_.end(); const size_type max_elements = std::distance(first_child, end); const container_iterator last_child = (max_elements > D) ? first_child + D : end; const container_iterator min_element = std::max_element(first_child, last_child, static_cast(*this)); return min_element - q_.begin(); } static size_type parent_index(size_type index) { return (index - 1) / D; } static size_type first_child_index(size_type index) { return index * D + 1; } size_type last_child_index(size_type index) const { const size_t first_index = first_child_index(index); const size_type last_index = (std::min)(first_index + D - 1, size() - 1); return last_index; } template struct rebind { typedef d_ary_heap, boost::heap::stability_counter_type, boost::heap::arity, boost::heap::compare, boost::heap::allocator >::type, X > other; }; template friend class priority_queue_mutable_wrapper; void update(size_type index) { if (index == 0) { siftdown(index); return; } size_type parent = parent_index(index); if (super_t::operator()(q_[parent], q_[index])) siftup(index); else siftdown(index); } void erase(size_type index) { while (index != 0) { size_type parent = parent_index(index); reset_index(index, parent); reset_index(parent, index); std::swap(q_[parent], q_[index]); index = parent; } pop(); } void increase(size_type index) { siftup(index); } void decrease(size_type index) { siftdown(index); } }; template struct select_dary_heap { static const bool is_mutable = extract_mutable::value; typedef typename mpl::if_c< is_mutable, priority_queue_mutable_wrapper >, d_ary_heap >::type type; }; } /* namespace detail */ /** * \class d_ary_heap * \brief d-ary heap class * * This class implements an immutable priority queue. Internally, the d-ary heap is represented * as dynamically sized array (std::vector), that directly stores the values. * * The template parameter T is the type to be managed by the container. * The user can specify additional options and if no options are provided default options are used. * * The container supports the following options: * - \c boost::heap::arity<>, required * - \c boost::heap::compare<>, defaults to \c compare > * - \c boost::heap::stable<>, defaults to \c stable * - \c boost::heap::stability_counter_type<>, defaults to \c stability_counter_type * - \c boost::heap::allocator<>, defaults to \c allocator > * - \c boost::heap::mutable_<>, defaults to \c mutable_ * */ #ifdef BOOST_DOXYGEN_INVOKED template #else template #endif class d_ary_heap: public detail::select_dary_heap::type>::type { typedef typename detail::d_ary_heap_signature::bind::type bound_args; typedef typename detail::select_dary_heap::type super_t; template friend struct heap_merge_emulate; #ifndef BOOST_DOXYGEN_INVOKED static const bool is_mutable = detail::extract_mutable::value; #define BOOST_HEAP_TYPEDEF_FROM_SUPER_T(NAME) \ typedef typename super_t::NAME NAME; struct implementation_defined { BOOST_HEAP_TYPEDEF_FROM_SUPER_T(size_type) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(difference_type) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(value_compare) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(allocator_type) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(reference) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_reference) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(pointer) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_pointer) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(iterator) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(const_iterator) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(ordered_iterator) BOOST_HEAP_TYPEDEF_FROM_SUPER_T(handle_type) }; #undef BOOST_HEAP_TYPEDEF_FROM_SUPER_T #endif public: static const bool constant_time_size = true; static const bool has_ordered_iterators = true; static const bool is_mergable = false; static const bool has_reserve = true; static const bool is_stable = super_t::is_stable; typedef T value_type; typedef typename implementation_defined::size_type size_type; typedef typename implementation_defined::difference_type difference_type; typedef typename implementation_defined::value_compare value_compare; typedef typename implementation_defined::allocator_type allocator_type; typedef typename implementation_defined::reference reference; typedef typename implementation_defined::const_reference const_reference; typedef typename implementation_defined::pointer pointer; typedef typename implementation_defined::const_pointer const_pointer; /// \copydoc boost::heap::priority_queue::iterator typedef typename implementation_defined::iterator iterator; typedef typename implementation_defined::const_iterator const_iterator; typedef typename implementation_defined::ordered_iterator ordered_iterator; typedef typename implementation_defined::handle_type handle_type; /// \copydoc boost::heap::priority_queue::priority_queue(value_compare const &) explicit d_ary_heap(value_compare const & cmp = value_compare()): super_t(cmp) {} /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue const &) d_ary_heap(d_ary_heap const & rhs): super_t(rhs) {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES /// \copydoc boost::heap::priority_queue::priority_queue(priority_queue &&) d_ary_heap(d_ary_heap && rhs): super_t(std::move(rhs)) {} /// \copydoc boost::heap::priority_queue::operator=(priority_queue &&) d_ary_heap & operator=(d_ary_heap && rhs) { super_t::operator=(std::move(rhs)); return *this; } #endif /// \copydoc boost::heap::priority_queue::operator=(priority_queue const &) d_ary_heap & operator=(d_ary_heap const & rhs) { super_t::operator=(rhs); return *this; } /// \copydoc boost::heap::priority_queue::empty bool empty(void) const { return super_t::empty(); } /// \copydoc boost::heap::priority_queue::size size_type size(void) const { return super_t::size(); } /// \copydoc boost::heap::priority_queue::max_size size_type max_size(void) const { return super_t::max_size(); } /// \copydoc boost::heap::priority_queue::clear void clear(void) { super_t::clear(); } /// \copydoc boost::heap::priority_queue::get_allocator allocator_type get_allocator(void) const { return super_t::get_allocator(); } /// \copydoc boost::heap::priority_queue::top value_type const & top(void) const { return super_t::top(); } /// \copydoc boost::heap::priority_queue::push typename mpl::if_c::type push(value_type const & v) { return super_t::push(v); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) /// \copydoc boost::heap::priority_queue::emplace template typename mpl::if_c::type emplace(Args&&... args) { return super_t::emplace(std::forward(args)...); } #endif /// \copydoc boost::heap::priority_queue::operator<(HeapType const & rhs) const template bool operator<(HeapType const & rhs) const { return detail::heap_compare(*this, rhs); } /// \copydoc boost::heap::priority_queue::operator>(HeapType const & rhs) const template bool operator>(HeapType const & rhs) const { return detail::heap_compare(rhs, *this); } /// \copydoc boost::heap::priority_queue::operator>=(HeapType const & rhs) const template bool operator>=(HeapType const & rhs) const { return !operator<(rhs); } /// \copydoc boost::heap::priority_queue::operator<=(HeapType const & rhs) const template bool operator<=(HeapType const & rhs) const { return !operator>(rhs); } /// \copydoc boost::heap::priority_queue::operator==(HeapType const & rhs) const template bool operator==(HeapType const & rhs) const { return detail::heap_equality(*this, rhs); } /// \copydoc boost::heap::priority_queue::operator!=(HeapType const & rhs) const template bool operator!=(HeapType const & rhs) const { return !(*this == rhs); } /** * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. * * \b Complexity: Logarithmic. * * \b Requirement: data structure must be configured as mutable * */ void update(handle_type handle, const_reference v) { BOOST_STATIC_ASSERT(is_mutable); super_t::update(handle, v); } /** * \b Effects: Updates the heap after the element handled by \c handle has been changed. * * \b Complexity: Logarithmic. * * \b Note: If this is not called, after a handle has been updated, the behavior of the data structure is undefined! * * \b Requirement: data structure must be configured as mutable * */ void update(handle_type handle) { BOOST_STATIC_ASSERT(is_mutable); super_t::update(handle); } /** * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. * * \b Complexity: Logarithmic. * * \b Note: The new value is expected to be greater than the current one * * \b Requirement: data structure must be configured as mutable * */ void increase(handle_type handle, const_reference v) { BOOST_STATIC_ASSERT(is_mutable); super_t::increase(handle, v); } /** * \b Effects: Updates the heap after the element handled by \c handle has been changed. * * \b Complexity: Logarithmic. * * \b Note: The new value is expected to be greater than the current one. If this is not called, after a handle has been updated, the behavior of the data structure is undefined! * * \b Requirement: data structure must be configured as mutable * */ void increase(handle_type handle) { BOOST_STATIC_ASSERT(is_mutable); super_t::increase(handle); } /** * \b Effects: Assigns \c v to the element handled by \c handle & updates the priority queue. * * \b Complexity: Logarithmic. * * \b Note: The new value is expected to be less than the current one * * \b Requirement: data structure must be configured as mutable * */ void decrease(handle_type handle, const_reference v) { BOOST_STATIC_ASSERT(is_mutable); super_t::decrease(handle, v); } /** * \b Effects: Updates the heap after the element handled by \c handle has been changed. * * \b Complexity: Logarithmic. * * \b Note: The new value is expected to be less than the current one. If this is not called, after a handle has been updated, the behavior of the data structure is undefined! * * \b Requirement: data structure must be configured as mutable * */ void decrease(handle_type handle) { BOOST_STATIC_ASSERT(is_mutable); super_t::decrease(handle); } /** * \b Effects: Removes the element handled by \c handle from the priority_queue. * * \b Complexity: Logarithmic. * * \b Requirement: data structure must be configured as mutable * */ void erase(handle_type handle) { BOOST_STATIC_ASSERT(is_mutable); super_t::erase(handle); } /** * \b Effects: Casts an iterator to a node handle. * * \b Complexity: Constant. * * \b Requirement: data structure must be configured as mutable * */ static handle_type s_handle_from_iterator(iterator const & it) { BOOST_STATIC_ASSERT(is_mutable); return super_t::s_handle_from_iterator(it); } /// \copydoc boost::heap::priority_queue::pop void pop(void) { super_t::pop(); } /// \copydoc boost::heap::priority_queue::swap void swap(d_ary_heap & rhs) { super_t::swap(rhs); } /// \copydoc boost::heap::priority_queue::begin const_iterator begin(void) const { return super_t::begin(); } /// \copydoc boost::heap::priority_queue::begin iterator begin(void) { return super_t::begin(); } /// \copydoc boost::heap::priority_queue::end iterator end(void) { return super_t::end(); } /// \copydoc boost::heap::priority_queue::end const_iterator end(void) const { return super_t::end(); } /// \copydoc boost::heap::fibonacci_heap::ordered_begin ordered_iterator ordered_begin(void) const { return super_t::ordered_begin(); } /// \copydoc boost::heap::fibonacci_heap::ordered_end ordered_iterator ordered_end(void) const { return super_t::ordered_end(); } /// \copydoc boost::heap::priority_queue::reserve void reserve (size_type element_count) { super_t::reserve(element_count); } /// \copydoc boost::heap::priority_queue::value_comp value_compare const & value_comp(void) const { return super_t::value_comp(); } }; } /* namespace heap */ } /* namespace boost */ #undef BOOST_HEAP_ASSERT #endif /* BOOST_HEAP_D_ARY_HEAP_HPP */