2026/2/5 14:50:16
网站建设
项目流程
查建设公司人员是那个网站,南京建站公司模板,三维制图培训班在哪里,网站开发企业排名基本特性头文件#xff1a;#include queue命名空间#xff1a;std底层实现#xff1a;通常基于堆#xff08;heap#xff09;数据结构实现默认行为#xff1a;大顶堆#xff08;最大元素优先出队#xff09;时间复杂度#xff1a;插入元素#xff1a;O(log n…基本特性头文件#include queue命名空间std底层实现通常基于堆heap数据结构实现默认行为大顶堆最大元素优先出队时间复杂度插入元素O(log n)删除顶部O(log n)访问顶部O(1)1.2 快速上手优先级队列常用操作详解优先级队列默认使用vector作为其底层存储数据的容器在vector上又使用了堆算法将vector中元素构造成堆的结构因此priority_queue就是堆所有需要用到堆的位置都可以考虑使用priority_queue。注意默认情况下priority_queue是大堆。函数声明接口说明priority_queue()/priority_queue(first, last)构造一个空的优先级队列注意priority_queue支持迭代器区间构造empty( )检测优先级队列是否为空是返回true否则返回falsetop( )返回优先级队列中最大(最小元素)即堆顶元素push(x)在优先级队列中插入元素xpop()删除优先级队列中最大(最小)元素即堆顶元素使用代码演示代码语言javascriptAI代码解释//priority_queue的头文件是queue #includequeue void test1() { //默认底层容器是vector大堆 //创建一个空的堆 priority_queueint pq; //插入数据 pq.push(20); pq.push(25); pq.push(19); pq.push(14); pq.push(44); //取堆顶数据 int top pq.top(); cout top endl; //打印数据 while (!pq.empty()) { cout pq.top() ; pq.pop(); } cout endl; //迭代器区间构造 vectorint v { 10,20,4,24,21,54 }; priority_queueint pq1(v.begin(), v.end()); while (!pq1.empty()) { cout pq1.top() ; pq1.pop(); } }运行结果那这时候就有一个问题那我们该怎么转换成使用小堆呢ok那这时候就需要我们传入第三个模板参数了。代码语言javascriptAI代码解释template class T, class Container vectorT, class Compare lesstypename Container::value_type class priority_queue;priority_queue中默认第三个模板参数是lesstypename Container::value_type表示的是小于的操作如果我们转换成使用小堆就要传入大于的操作直接上代码代码语言javascriptAI代码解释//priority_queue的头文件queue #includequeue //greater的头文件functional #includefunctional void test2() { //转换成小堆 //第三个模板参数greaterint表示的是大于 priority_queueint,vectorint,greaterint pq; //插入数据 pq.push(20); pq.push(25); pq.push(19); pq.push(14); pq.push(44); //取堆顶数据 int top pq.top(); cout top endl; //打印数据 while (!pq.empty()) { cout pq.top() ; pq.pop(); } cout endl; }二、优先级队列的底层实现容器适配与堆算法2.1 关键接口的代码实现(注意看注释)代码语言javascriptAI代码解释#includeiostream #includevector using namespace std; namespace carrot { templateclass T,class ContainervectorT class priority_queue { public: void Adjust_up(int child) { int parent (child - 1) / 2; while (child 0) { //比较孩子和父节点的大小大就交换 if (_con[parent] _con[child]) { swap(_con[parent], _con[child]); child parent; parent (child - 1) / 2; } else { break; } } } void Adjust_down(int parent) { int child parent * 2 1; while (child _con.size()) { //找出左右孩子中较大的一个 if (child 1 _con.size() _con[child 1] _con[child]) { child; } //比较较大孩子和父节点的大小大就交换否则不交换 if (_con[parent] _con[child]) { swap(_con[parent], _con[child]); parent child; child parent * 2 1; } else { break; } } } void push(const T x) { _con.push_back(x); //向上调整 Adjust_up(_con.size() - 1); } void pop() { swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); //向下调整使其还是一个大堆 Adjust_down(0); } size_t top() { return _con[0]; } bool empty() { return _con.empty(); } size_t size() { return _con.size(); } private: //底层容器 Container _con; }; }上面的代码实现的是默认大堆操作那我们该怎么转换成小堆操作呢是直接将向上调整和向下调整代码中的孩子大于父节点转成孩子小于父节点吗这很明显有点不太符合实际那该怎么做呢ok这时候就要引出第三个模板参数在C中尽量不用使用函数指针C就搞出了仿函数这个类型的对象就可以像函数一样取使用那我们该怎么让这个仿函数成为这第三个模板参数呢看代码代码语言javascriptAI代码解释templateclass T struct Less { bool operator()(const T x, const T y) { return x y; } }; templateclass T struct greater { bool operator()(const T x, const T y) { return x y; } }; //默认是大堆第三个模板参数给缺省值为LessT templateclass T, class Containor vectorT, class Compare LessT class priority_queue { public: //迭代器区间的构造 template class InputIterator priority_queue(InputIterator first, InputIterator last) :_con(first, last)//调用_con容器的迭代器区间构造 { //向下调整建堆 for (int i (_con.size() - 1 - 1) / 2; i 0; i--) { Adjust_down(i); } } //有了迭代器区间的构造就不会生成默认构造了 priority_queue() { } //向上调整算法 void Adjust_up(int child) { Compare com;//com 这个对象可以像函数一样取使用 int parent (child - 1) / 2; while (child 0) { //比较孩子和父亲的大小大就交换小就不交换 //if (_con[child] _con[parent]) //if (_con[parent]_con[child]) if (com(_con[parent], _con[child])) { swap(_con[child], _con[parent]); child parent; parent (child - 1) / 2; } else { break; } } } //向下调整算法 void Adjust_down(int parent) { Compare com; int child parent * 2 1; while (child _con.size()) { //找出左右孩子中较大的一个 //if (child 1 _con.size() _con[child] _con[child 1]) if (child 1 _con.size() com(_con[child], _con[child 1])) { child; } //比较较大孩子和父节点的大小大就交换 //if (_con[child] _con[parent]) //if (_con[parent]_con[child]) if (com(_con[parent], _con[child])) { swap(_con[child], _con[parent]); parent child; child parent * 2 1; } else { break; } } } //插入数据 void push(const T x) { _con.push_back(x); //调整数据使其还是一个大堆 //向上调整 Adjust_up(_con.size() - 1); } //删除堆顶数据 void pop() { swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); //向下调整使其还是一个大堆 Adjust_down(0); } //取堆顶数据 const T top() const { return _con[0]; } //判断是否为空 bool empty() const { return _con.empty(); } private: Containor _con; };在上面的代码中博主实现了两个仿函数然后我们就可以用LessT作为第三个模板参数默认是大堆。如果想转成小堆结构就可以显示的传第三个模板参数为greater类型这样我们就可以转成小堆结构所谓的仿函数就是这个类型的对象可以像函数一样的调用ok接下来我们来看一下仿函数的相关知识这里只是简单的看一下三、仿函数通过上面的比较的仿函数的学习我们应该掌握了基础的仿函数写法和运用比较的仿函数除了可以像上面一样的使用还可以控制更加复杂的东西。