个人主页:Lei宝啊
愿所有美好如期而遇
Container就是适配器,也就是说这个优先级队列的底层就使用vector,当然,我们也可以使用deque来适配,但是对于优先级队列来说,效率是低于vector的,因为优先级队列本质就是堆,我们需要用到下标来进行向上或者向下调整,而deque虽然可以使用下标索引,同时也具备链式结构,但是单独拉出来一个功能效率是不如vector和queue的,所以使用deque适配的效率不如vector,同时这里是不能用queue来适配的。
上面我们也可以看见Compare默认是less,也就是说优先级队列默认是建大堆的(尽管使用less建大堆,greater建小堆看着很难受,但库就是这么实现的)。
push方法,就是向优先级队列里插入元素,同时调整成堆,pop方法,就是删除堆顶元素,同时向下调整维持堆的结构。
其他方法我们不多赘述,接下来开始模拟实现优先级队列。
首先将Compare仿函数实现出来,这里就要介绍什么是仿函数:
template<class T>class Less{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T>class Greater{public:bool operator()(const T& x, const T& y){return x < y;}};
我们平时调用函数时是这样:比如有一个int add(int a,int b)函数,我们调用时是这样add(1,2),那么仿函数就是:类里重载了()运算符的operator(),使得这个类使用起来像一个函数。
我们使用时先创建这个类的对象,比如Less compare; 然后比较大小就是这样:compare(1,2),是不是很类似于函数?
接着就是优先级队列的内部构造:
其中的核心也就是堆向上调整,堆向下调整,数据的插入和删除,也就这么四个核心点,type就是我们要适配的容器。
//默认建大堆template<class T, class type = vector<int>, class compare = Less<T>>class priority_queue{public:priority_queue() {};template <class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){q.push_back(*first);judge_up(size() - 1);first++;}}bool empty() const{return q.empty();}int size() const{return q.size();}T& top(){return q.front();}const T& top() const{return q.front();}void judge_up(int child){int parent = (child - 1) / 2;while (child){if (com(q[child], q[parent])){swap(q[child], q[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){q.push_back(x);judge_up(size() - 1);}void judge_down(int parent){int child = parent * 2 + 1;while (child < size()){if (child + 1 < size() && !com(q[child], q[child + 1])){child++;}if (com(q[child], q[parent])){swap(q[child], q[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(q[0], q[size() - 1]);q.erase(q.end() - 1);judge_down(0);}private:type q;compare com;};}