自从学过数据结构中的堆以后每次想到大堆和小堆的代码就很头疼,最近学了优先队列(priority_queue)后,发现模拟实现优先队列正好用到了大堆小堆的知识,在这里记录一下加深记忆,同时方便以后查看。
模拟实现代码如下:
namespace my_space
{
template<class T>
struct less
{
bool operator()(const T& left, const T& right)
{
return left < right;
}
};
//仿函数(仿函数就是一个类,在这个类里仅仅是重载了一个小括号,
//仿函数只有一元仿函数和二元仿函数,根据参数个数确定)
//仿函数就是用起来像函数的类
template<class T>
struct greater
{
bool operator()(const T& left, const T& right)
{
return left > right;
}
};
template<class T, class Cont = vector<T>, class Pred = less<T> >
class priority_queue
{
public:
typedef T value_type;
typedef size_t size_type;
priority_queue()
{}
priority_queue(const value_type *first, const value_type *last)
{
while (first != last)
c.push_back(*first++);
int root = (c.size() - 1) / 2; //找到二叉树的最后面一个需要向下调的节点
while (root >= 0)
adjustdown(root--);
}
bool empty() const
{
return c.empty();
}
size_type size() const
{
return c.size();
}
value_type& top()
{
assert(!empty());
return c.front();
}
const value_type& top() const
{
assert(!empty());
return c.front();
}
void push(const value_type &x)
{
c.push_back(x);
adjustup(c.size() - 1);
}
void pop()
{
std::swap(c.front(), c.back());
c.pop_back();
adjustdown(0);
}
protected:
void adjustdown(int parent)
{
int child = 2 * parent + 1;
while (child < c.size())
{
if (child + 1 < c.size() && comp(c[child], c[child + 1]))
++child;
if (comp(c[parent], c[child])) //-->comp.operator(c[parent], c[chid])
{
std::swap(c[parent], c[child]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void adjustup(int child)
{
int parent = (child - 1) / 2;
while (child)
{
if (comp(c[parent], c[child]))
{
std::swap(c[parent], c[child]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
private:
Cont c;
Pred comp;
};
}
测试代码1:
int main()
{
my_space::priority_queue<int> pq;
pq.push(1);
pq.push(7);
pq.push(2);
pq.push(3);
pq.push(9);
pq.push(4);
pq.push(5);
cout << pq.top() << endl;
pq.pop();
cout << pq.top() << endl;
return 0;
}
测试代码2:
void main()
{
int v[] = { 5, 7, 8, 2, 9, 3, 1, 0 };
int n = sizeof(v) / sizeof(v[0]);
my_space::priority_queue<int, vector<int>, my_space::greater<int> > pq(v, v + n);
while (!pq.empty())
{
cout << "top = " << pq.top() << endl;
pq.pop();
}
}
我注意到在我们调用make_heap函数产生小堆时,调用方式如下:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
vector<int> v = { 5, 7, 9, 30, 4, 1, 0, 2 };
for (const auto &e : v)
cout << e << " ";
cout << endl;
//生成一个小堆
make_heap(v.begin(), v.end(), greater<int>());
for (const auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
但是在优先队列生成小堆时如下:
my_space::priority_queue<int, vector<int>, my_space::greater<int> > pq(v, v + n);
他们的区别在于一个是greater<int>()
,另一个是greater<int>
,一个有小括号,另一个没有小括号,原因就是make_heap()是一个函数,所以参数需要传入一个临时对象,greater<int>()
就是生成一个greater<int>
类型的无名临时对象,而优先队列是一个模板类,我们传入的是一个类类型greater<int>
,所以没有小括号。