文章目录
1. priority_queue的介绍和使用
1.1 priority_queue的介绍
priority_queue(优先队列)是 C++ 标准模板库(STL)中的一个容器适配器,它提供了一种按照优先级自动排序的队列数据结构。与普通队列的 “先进先出(FIFO)” 不同,优先队列中元素的出队顺序取决于其优先级,优先级最高的元素总是最先被弹出。
核心特性:
自动排序:插入元素时会自动按照预设的优先级规则排序(默认是降序,即最大元素优先)。
访问限制:只能访问优先级最高的元素(队首),无法直接访问其他位置的元素。
基于底层容器:默认使用 vector 作为底层容器,也可指定为 deque 等序列容器。
排序准则:默认使用 less(大顶堆,最大值优先), greater(小顶堆,最小值优先)也可自定义比较器实现小顶堆或其他排序规则。

1.2 priority_queue的使用
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成
堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:
默认情况下priority_queue是大堆。
头文件<queue>
| 函数声明 | 接口说明 |
|---|---|
| priority_queue() | 构造一个空的优先级队列 |
| priority_queue(first, last) | 以一个迭代器区间构造优先级队列 |
| empty( ) | 检测优先级队列是否为空,是返回true,否则返回false |
| top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
| push(x) | 在优先级队列中插入元素x |
| pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
vector<int> v{ 1,3,9,5,8,4,6 };
priority_queue<int> pq();
priority_queue<int> pq1(v.begin(),v.end());
while (!pq1.empty())
{
cout << pq1.top();
pq1.pop();
}

2. 仿函数
2.1 仿函数的定义
在 C++ 中,仿函数(Functor) 是一种行为类似函数的对象,它通过重载 operator() 运算符,使得对象可以像函数一样被调用。这种特性让仿函数兼具函数的灵活性和对象的状态存储能力,在 STL(标准模板库)中被广泛用于算法的参数(如排序、查找的自定义规则)。
仿函数的基本定义
仿函数通常是一个类(或结构体),其中重载了 operator(),语法如下:
tempalte<class T>
class less
{
public:
bool operator()(T a,T b)
{
return a<b;
}
}
2.2 仿函数的使用
- 使用时,先创建类的对象,再像调用函数一样使用 对象名(参数) 触发 operator() 的执行。
less<int> ls;
std::cout<<ls(3,4);

3小于4,返回真。
- 也可以通过匿名对象的形式调用仿函数:
std::cout<<less<int>()(2,4);

先用less()创建一个匿名对象,然后再利用()符号重载调用仿函数。
3. 利用仿函数模拟priority_queue
1. class priority_queue的成员类型:
template <class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
public:
private:
Container c;//使用适配器,默认为vector。
Compare comp;//比较类,里面有比较的函数。
};
注意:compare为less时,优先队列为大堆,compare为greater时,优先队列为小堆。
Compare comp;比较类,里面有比较的仿函数。默认为less,less内有对符号()重载,大概为:
template <class T>
class less
{
bool operator()(const T&a,const T&b)
{
return a<b;
}
}
2. class priority_queue的拷贝构造:
priority_queue()
{
};
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
c.push_back(*(first++));
adjust_up();
}
}
priority_queue可以使用迭代器区间,构造优先队列。其原理是对底层的vector或deque进行尾插,每插入一个元素,进行从插入位置向上调整,这里我们默认的是less,所以是一个大堆,把大的值向上调整。

向上调整代码:
void adjust_up()
{
int child = c.size() - 1;
int parent = (child - 1) / 2;
while (comp(c[parent], c[child]) && parent >= 0)
{
swap(c[parent], c[child]);
child = parent;
parent = (child - 1) / 2;
}
}
注意:我们默认的比较仿函数是less中的operator(),也就是比较小的话为真,这是堆为大堆,也就是堆顶为最大元素。comp(c[parent], c[child]),也就是parent小于child时,交换两个位置的元素,这样就可以让child节点,也就是向上调整时,下面的大于上面的元素上移。
3. 插入函数
void push(const T& x)
{
c.push_back(x);
adjust_up();
};
4. 删除函数
void pop()
{
swap(c[0], c[c.size() - 1]);
c.pop_back();
adjust_down();
};

向下调整代码:
void adjust_down()
{
int parent = 0;
int child = parent * 2 + 1;
while (child<c.size())
{
if (comp(c[child], c[child + 1]) && child + 1 < c.size())
child += 1;
if (comp(c[parent], c[child]))
{
swap(c[parent], c[child]);
parent = child;
child= parent * 2 + 1;
}
else
{
break;
}
}
}
注意:我们默认的比较仿函数是less中的operator(),也就是比较小的话为真,这是堆为大堆,也就是堆顶为最大元素。comp(c[parent], c[child]),也就是parent小于child时,交换两个位置的元素,这样就可以使上面小的元素和小面大的元素交换位置。
5. 整体代码:
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)
{
c.push_back(*(first++));
adjust_up();
}
}
void adjust_up()//向上调整堆
{
int child = c.size() - 1;
int parent = (child - 1) / 2;
while (comp(c[parent], c[child]) && parent >= 0)
{
swap(c[parent], c[child]);
child = parent;
parent = (child - 1) / 2;
}
}
void adjust_down()//向下调整堆
{
int parent = 0;
int child = parent * 2 + 1;
while (child<c.size())
{
if (comp(c[child], c[child + 1]) && child + 1 < c.size())
child += 1;
if (comp(c[parent], c[child]))
{
swap(c[parent], c[child]);
parent = child;
child= parent * 2 + 1;
}
else
{
break;
}
}
}
bool empty() const//堆是否为空
{
return c.empty();
};
size_t size() const//堆中元素多少
{
return c.size();
};
const T& top() const//访问堆顶元素
{
return c.front();
};
void push(const T& x)//插入元素
{
c.push_back(x);
adjust_up();
};
void pop()//删除堆顶
{
swap(c[0], c[c.size() - 1]);
c.pop_back();
adjust_down();
};
private:
Container c;
Compare comp;
};
4. 如何创建小堆优先级队列
我们想创建小堆,可以再创建优先级队列时,在模板实例化时,传greater:
priority_queue<int,vector<int>,greater<int>> p();
因为greater和less比较逻辑是相反的,所以创建出来的是一个小堆。
4290

被折叠的 条评论
为什么被折叠?



