文章目录
- 一、priority_queue接口使用
- 二、 priority_queue模拟实现
- 三、模拟代码总览
一、priority_queue接口使用
1、函数接口与作用
接口 | 作用 |
---|---|
priority_queue< T > | 构造一个空优先队列 |
priority_queue< T >(迭代区间) | 通过迭代区间构造一个优先队列 |
push(val) | val入队 |
pop() | 出队 |
size() | 队列的元素个数 |
top() | 取出队头元素的引用 |
empty() | 判断栈是否为空 |
2、指定排序规则
在定义优先队列时指定,如果不指定就默认倒序(大堆)。
如何指定:
比较仿函数写法:
//比较仿函数
template <class T>
class cmp
{
public:
//返回bool,两个参数
bool operator()(T& x, T& y)
{
//比较........
return x > y;
}
};
3、使用
void priority_queue_test()
{
//通过迭代器区间构造
vector<int> v{ 1,2,5,3,8 };
//默认大堆
priority_queue<int> q(v.begin(),v.end());
//判断是否为空
while (!q.empty())
{
//取队头元素
cout << q.top() << " ";
//出队
q.pop();
}
cout << endl;
}
二、 priority_queue模拟实现
1、 priority_queue
是一个适配器,默认封装了vector
容器,所以我们模拟时也使用vector
容器。
2、priority_queue框架
//第一个是数据类型,第二个是容器类型(默认vector),第三个仿函数类的类型(默认大堆)
template <class T,class Container = vector<T> , class Compare = less<T>>
class priority_queue
{
public:
void push(T x);
//....
private:
Container c;
}
3、比较仿函数类的实现
大堆:
template <class T>
class less
{
public:
bool operator()(const T& a, const T& b)
{
return a < b;
}
};
小堆:
template <class T>
class greater
{
public:
bool operator()(const T& a, const T& b)
{
return a > b;
}
};
4、插入、删除
(1)push
这里直接复用vector
容器的push_back
接口,但是我们需要将优先级最高的放到第一个位置,所以还需要使用一个堆的向上调整算法,该算法需要配合比较仿函数使用。
//向上调整算法
void Adjust_Up(size_t child)
{
size_t father = (child - 1) / 2;
T tmp = c[child];
//仿函数类
Compare cmp;
while (child > 0)
{
//使用仿函数判断
if(cmp(c[father], tmp))
{
c[child] = c[father];
child = father;
father = (child - 1) / 2;
}
else
break;
}
c[child] = tmp;
}
void push(const T& x)
{
//利用vector的接口
c.push_back(x);
//使用向上调整算法
Adjust_Up(size() - 1);
}
(2)pop
我们需要将第一个位置的元素删掉,为了保证效率,需要将其与最后一个元素交换,再进行尾删(这样效率比直接删除第一个位置高),最后使用向下调整算法即可保持优先级最高的在第一个位置了。
//先下调整算法
void Adjust_Down()
{
size_t father = 0;
size_t child = father * 2 + 1;
T tmp;
//仿函数对象
Compare cmp;
if (size() > 0)
tmp = c[0];
else return;
while (child < size())
{
//使用仿函数比较
if (child + 1 < size() && cmp(c[child],c[child + 1]))
child++;
//使用仿函数比较
if(cmp(tmp, c[child]))
{
c[father] = c[child];
father = child;
child = father * 2 + 1;
}
else
break;
}
c[father] = tmp;
}
//删除
void pop()
{
//先交换
std::swap(c[0], c[size() - 1]);
//再尾删
c.pop_back();
//最后向下调整
Adjust_Down();
}
5、其他接口
都是复用vector
接口实现
//判断是否为空
bool empty() const
{
return c.empty();
}
//大小
size_t size() const
{
return c.size();
}
//取队头元素引用
T& top()
{
return c[0];
}
6、构造函数
//默认构造
priority_queue()
{};
//使用迭代器区间构造,直接复用push这个接口即可
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
push(*first);
++first;
}
}
三、模拟代码总览
namespace xu
{
template <class T>
class less
{
public:
bool operator()(const T& a, const T& b)
{
return a < b;
}
};
template <class T>
class greater
{
public:
bool operator()(const T& a, const T& b)
{
return a > b;
}
};
template <class T,class Container = vector<T> , class Compare = less<T>>
class priority_queue
{
public:
priority_queue()
{};
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
push(*first);
++first;
}
}
void Adjust_Up(size_t child)
{
size_t father = (child - 1) / 2;
T tmp = c[child];
Compare cmp;
while (child > 0)
{
//if (c[father] < tmp)
if(cmp(c[father], tmp))
{
c[child] = c[father];
child = father;
father = (child - 1) / 2;
}
else
break;
}
c[child] = tmp;
}
void Adjust_Down()
{
size_t father = 0;
size_t child = father * 2 + 1;
T tmp;
Compare cmp;
if (size() > 0)
tmp = c[0];
else return;
while (child < size())
{
//if (child + 1 < size() && c[child] < c[child + 1])
if (child + 1 < size() && cmp(c[child],c[child + 1]))
child++;
//if (tmp < c[child])
if(cmp(tmp, c[child]))
{
c[father] = c[child];
father = child;
child = father * 2 + 1;
}
else
break;
}
c[father] = tmp;
}
bool empty() const
{
return c.empty();
}
size_t size() const
{
return c.size();
}
T& top()
{
return c[0];
}
void push(const T& x)
{
c.push_back(x);
Adjust_Up(size() - 1);
}
void pop()
{
std::swap(c[0], c[size() - 1]);
c.pop_back();
Adjust_Down();
}
private:
Container c;
};
};
测试:
void test01()
{
//默认构造
xu::priority_queue<int> q;
//插入
q.push(1);
q.push(3);
q.push(2);
q.push(4);
q.push(4);
q.push(5);
q.push(6);
//判断
while (!q.empty())
{
//队头元素
cout << q.top() <<" ";
//出队
q.pop();
}
cout << endl;
}
void test02()
{
vector<int> v{ 1,2,5,3,8 };
//迭代器区间构造
xu::priority_queue<int, vector<int>, xu::greater<int>> q(v.begin(),v.end());
while (!q.empty())
{
cout << q.top() << " ";
q.pop();
}
cout << endl;
}