做网站备案要多久,福州网建公司,和文化有关的吉网站建设模板,建设银行公积金预约网站首页1 .了解优先级队列 优先级队列是一种容器适配器#xff0c;根据一些严格的弱排序标准#xff0c;专门设计使其第一个元素始终是它所包含的元素中最大的元素。 此上下文类似于堆#xff0c;其中可以随时插入元素#xff0c;并且只能检索最大堆元素#xff08;优先级队列中顶…1 .了解优先级队列 优先级队列是一种容器适配器根据一些严格的弱排序标准专门设计使其第一个元素始终是它所包含的元素中最大的元素。 此上下文类似于堆其中可以随时插入元素并且只能检索最大堆元素优先级队列中顶部的元素。 优先级队列是作为容器适配器实现的容器适配器是使用特定容器类的封装对象作为其底层容器的类提供一组特定的成员函数来访问其元素。元素是从特定容器的“背面”弹出的该容器称为优先级队列的顶部。 基础容器可以是任何标准容器类模板也可以是其他一些专门设计的容器类。容器应通过随机访问迭代器访问并支持以下操作 empty()size()front()push_back()pop_back() 标准容器类并满足这些要求。默认情况下如果未为特定类实例指定容器类则使用标准容器。 需要支持随机访问迭代器以便始终在内部保持堆结构。这是由容器适配器通过自动调用算法函数自动完成的并在需要时自动完成。vector、deque、priority_queue、vector、make_heappush_heap、pop_heap
2.优先级队列的相关接口
优先级队列的接口有如下几种。对于优先级队列我们默认是它的大的数优先级高。其底层是一个堆。也就是说我们默认是大堆所以大的数优先级高。如果是一个小堆那么就是小的优先级高
1.常用接口函数 我们来随便使用一下这些接口吧
#includeiostream
#includevector
#includequeue
using namespace std;void test_priority_queue()
{priority_queueint pq;pq.push(123);pq.push(1045);pq.push(2);pq.push(3);pq.push(4);while (!pq.empty()){cout pq.top() ;pq.pop();}cout endl;
}int main()
{test_priority_queue();
}运行结果 可以看到默认是一个大堆但是我们会注意到它库里面默认传的是less但是却是一个大堆这里需要额外注意一下。 如果想要是一个小堆的话我们需要将这个less替换为greater
#includeiostream
#includevector
#includequeue
using namespace std;void test_priority_queue()
{priority_queueint,vectorint,greaterint pq;pq.push(123);pq.push(1045);pq.push(2);pq.push(3);pq.push(4);while (!pq.empty()){cout pq.top() ;pq.pop();}cout endl;
}int main()
{test_priority_queue();
}运行结果: 在这里我们传的lessgreater这些也称之为仿函数。也就是说通过仿函数控制实现大小堆.除此之外这里除了可以传vector以外还可以传递deque但是由于堆需要大量访问[]运算符所以deque的效率不高。
2.构造函数
如下所示可以无参构造也可以用迭代器区间进行初始化。 3.优先队列的模拟实现
优先级队列主要还是堆的逻辑的实现。即堆的构造向上调整和向下调整。
这些我们在数据结构讲过了,我直接上源码了 templateclass T, class Container vectorTclass priority_queue{private:void AdjustDown(int parent){int child parent * 2 1;while (child_con.size()){if (child 1 _con.size() _con[child] _con[child 1]){child;}if (_con[child] _con[parent]){swap(_con[child], _con[parent]);parent child;child parent * 2 1;}else{break;}}}void AdjustUp(int child){int parent (child - 1) / 2;while (child 0){if (_con[child] _con[parent]){swap(_con[child], _con[parent]);child parent;parent (child - 1) / 2;}else{break;}}}public:templateclass InputIteratorpriority_queue(InputIterator first, InputIterator last){while (first ! last){_con.push_back(*first);first;}for (int i (_con.size() - 1 - 1) / 2; i 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};既然这些容器都学完了这里附上我的一道错题
假设cont是一个Container 的示例里面包含数个元素那么当CONTAINER为
1.vector 2.list 3.deque 会导致下面的代码片段崩溃的Container 类型是
int main()
{
Container cont { 1, 2, 3, 4, 5};
Container::iterator iter, tempIt;
for (iter cont.begin(); iter ! cont.end();)
{
tempIt iter;
iter;
cont.erase(tempIt);
}
}
A.1, 2
B.2, 3
C.1, 3
D.1, 2, 3
答案选择C 解析 各个容器的erase(pos)实现 1. vectorerase(pos)直接把pos1到finish的数据拷贝到以pos为起点的区间上也就是vector的长度会逐渐变短同时iter会逐渐往后移动直到iter cont.end()由于容器中end()返回的迭代器是最后一个元素的下一个这个地方没有任何值现在考虑这个状态前一个状态此时要删除的点是iter, tempIt iter, iter会指向此时的end()但是执行erase(tempIt)之后end()向前移动了问题来了此时iter空了不崩溃才怪。 2. listerase(pos)干的事情很简单删除自己前后的节点连接起来就完了所以iter自增的过程不会指空不会崩溃喽。 3.dequeerase(pos)与vector的erase(pos)有些类似基于结构的不同导致中间有些步骤不太一致。先说说deque的结构这个结构本身比较复杂拣重要说吧具体看STL源码它是一个双向开口的连续线性空间实质是分段连续的由中控器map维持其整体连续的假象。其实题中只要知道它是双向开口的就够了可以在头部或尾部增加、删除。在题中有erase(pos)deque是这样处理的如果pos之前的元素个数比较少那么把start到pos-1的数据移到起始地址为start1的区间内否则把pos后面的数据移到起始地址为pos的区间内。在题中iter一直往后移动总会出现后面数据比前面少的时候这时候问题就和1一样了必须崩溃 解析思路来源会导致上面的代码片段崩溃的CONTAINER类型是_完美世界笔试题_牛客网 来源牛客网 4.仿函数
1.仿函数介绍
我们知道对于优先级队列可以用仿函数改变其是大堆还是小堆。根据底层逻辑可知仿函数应该就是改变了大小比较。才改变的行为。我们可以写一个简单的仿函数类
如下所示就是一个最简单的仿函数 class less{public:bool operator()(int x, int y){return x y;}};这样我们就可以类似于一个函数一样进行比较大小了仿函数即函数对象可以让类对象像函数一样使用
有了仿函数我们就可以在前面的优先级队列中使用仿函数来切换大堆小堆了。在C语言中我们想要实现这个功能只有使用函数指针。而这个仿函数就刚好可以替换掉函数指针。因为函数指针的弊端太明显了它太过于复杂了可读性不好。 2.优先级队列添加仿函数 templateclass T, class Container vectorT, class Compare lessTclass priority_queue{private:void AdjustDown(int parent){Compare com;int child parent * 2 1;while (child_con.size()){if (child 1 _con.size() com(_con[child], _con[child 1])){child;}if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent child;child parent * 2 1;}else{break;}}}void AdjustUp(int child){Compare com;int parent (child - 1) / 2;while (child 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child parent;parent (child - 1) / 2;}else{break;}}}public:templateclass InputIteratorpriority_queue(InputIterator first, InputIterator last){while (first ! last){_con.push_back(*first);first;}for (int i (_con.size() - 1 - 1) / 2; i 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};templateclass Tclass less{public:bool operator()(const T x, const T y){return x y;}};templateclass Tclass greater{public:bool operator()(const T x, const T y){return x y;}};
3.需要自己写仿函数的情形
我们的上面的仿函数是模拟库里面的行为上面的仿函数在库里面早已给出我们无需自己动手写。但是有时候我们也需要自己去写一个仿函数。
如我们存储的是一个指针而不是一个对象等情况
struct LessTime
{bool operator()(Time* x, Time* y){return *x *y;}
};5.优先级队列完整代码 templateclass T, class Container vectorT, class Compare lessTclass priority_queue{private:void AdjustDown(int parent){Compare com;int child parent * 2 1;while (child_con.size()){if (child 1 _con.size() com(_con[child], _con[child 1])){child;}if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent child;child parent * 2 1;}else{break;}}}void AdjustUp(int child){Compare com;int parent (child - 1) / 2;while (child 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child parent;parent (child - 1) / 2;}else{break;}}}public:templateclass InputIteratorpriority_queue(InputIterator first, InputIterator last){while (first ! last){_con.push_back(*first);first;}for (int i (_con.size() - 1 - 1) / 2; i 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};templateclass Tclass less{public:bool operator()(const T x, const T y){return x y;}};templateclass Tclass greater{public:bool operator()(const T x, const T y){return x y;}};