【发布时间】:2014-01-06 15:18:44
【问题描述】:
我一直在使用二进制堆处理优先级队列,并为此开发了一个类,如下所示。
#include <iostream>
#include <type_traits>
template<class T, int N>
class BinaryHeap{
template<class T1>
class has_less_than_operator
{
private:
class no{};
template<class X>
static auto has(X&& t) -> decltype (t.operator < (t));
static no has(...);
public:
enum {
value = !std::is_same<
decltype(has( std::declval<T1>() )),
no>::value
};
};
static_assert(std::is_copy_assignable<T>::value &&
std::is_copy_constructible<T>::value,
"Must be copy assignable and constructable");
public:
BinaryHeap() : used_(0){
}
BinaryHeap(BinaryHeap const& other) = default;
BinaryHeap& operator = (BinaryHeap const& other) = default;
inline T& max(){
return elements_[FIRST];
}
inline T const & max() const{
return elements_[FIRST];
}
void insert(T const& item){
elements_[++used_] = item;
swim(used_);
}
inline bool full() const{
return used_ == N;
}
void deleteMax(){
std::swap(elements_[used_],elements_[FIRST]);
sink(FIRST);
elements_[used_--] = T();
}
private:
template<class T1>
class has_dereference_operator
{
private:
class no{};
template<class X>
static auto has(X&& t) -> decltype (t.operator * ());
static no has(...);
public:
enum {
value = !std::is_same<
decltype(has( std::declval<T1>() )),
no>::value
};
};
inline bool parent_less(int position,std::integral_constant<int,0> i){
return elements_[ position / 2] < elements_[position];
}
inline bool parent_less(int position,std::integral_constant<int,1> i){
return *(elements_[ position / 2]) < *(elements_[position]);
}
void swim(int position){
while(position > 1 && parent_less(position,std::integral_constant<int, has_dereference_operator<T>::value>()))
{
std::swap(elements_[ position / 2], elements_[position]);
position /= 2;
}
}
inline int which_less(int p1, int p2, std::integral_constant<int,0> i){
return (elements_[ p1] < elements_[p2]) ? p1 : p2;
}
inline int which_less(int p1, int p2, std::integral_constant<int,1> i){
return (*(elements_[ p1]) < *(elements_[p2])) ? p1 : p2;
}
inline int which_greater(int p1, int p2, std::integral_constant<int,0> i){
return (elements_[ p1] < elements_[p2]) ? p2 : p1;
}
inline int which_greater(int p1, int p2, std::integral_constant<int,1> i){
return (*(elements_[ p1]) < *(elements_[p2])) ? p2 : p1;
}
void sink(int position){
while(position * 2 <= used_){
int first = position * 2;
if(first > used_) break;
int greater_child = which_greater(first, first + 1, std::integral_constant<int, has_dereference_operator<T>::value>());
int lesser = which_less(greater_child, position, std::integral_constant<int, has_dereference_operator<T>::value>());
if(lesser == greater_child)
break;
std::swap(elements_[greater_child], elements_[position]);
position = greater_child;
}
}
inline int current_position() const{
return used_ + 1;
}
static const int MAX = N + 1;
static const int FIRST = 1;
static const int LAST = N;
T elements_[MAX];
int used_;
};
int main(int argc, const char * argv[])
{
BinaryHeap<int, 10> b;
b.insert(1);
b.insert(20);
b.insert(21);
b.insert(3);
b.insert(2);
std::cout << "Max: " << b.max() << std::endl;
b.deleteMax();
std::cout << "Max: " << b.max() << std::endl;
return 0;
}
虽然我有这个工作,但我需要处理比较指针/共享指针说使用解引用运算符和值只是按原样使用它们的差异。我目前正在使用 SFINAE 根据该类是否具有运算符 * 来执行此操作。
这是实现这一目标的正确方法吗?
布莱尔
【问题讨论】:
-
我不确定为什么在有
std::priority_queue时实现优先级队列,在有std::make_heap等时实现二进制堆。除此之外,为什么要根据提供的类型更改行为?您可以改用包装器或谓词。 -
这实际上不是重点。它是一种学习练习。我知道 std::priority_queue。
-
惯用的交换方式是
using std::swap; swap(foo, bar);。这将调用特定类型的swap(T&, T&)(如果存在),如果不存在则回退到std::swap。 -
您的
has_foo特征不适用于非成员运算符重载。不是检查成员的类型,而是检查表达式的结果类型,例如,decltype(t < t)和decltype(*t)
标签: c++ templates sfinae compile-time