stack、queue、priority_queue的使用
stack
参考:http://www.cplusplus.com/reference/stack/stack/stack/
stack是一种先进后出的数据结构,它允许新增元素、移除元素、取得最顶部元素。除了最顶端外,没有其他方法可以存取stack的其他元素。
stack不提供遍历功能,所以没有迭代器。
类模板声明
template <class T, class Container = deque<T> > class stack;
头文件
#include <stack>
初始化
//注意:下面所有的ctnr容器都是跟stack模板声明中的class Container=deque<T>对应的,默认是deque<T>
//所以默认情况下,下面的ctnr都是deque容器
//复制ctnr容器来构造一个stack
explicit stack (const container_type& ctnr);
//移动ctnr容器来构造一个stack
explicit stack (container_type&& ctnr = container_type());
//默认无参构造
template <class Alloc> //可以指定内存分配器
explicit stack (const Alloc& alloc);
//复制ctnr容器来构造一个stack
template <class Alloc> //可以指定内存分配器
stack (const container_type& ctnr, const Alloc& alloc);
//移动ctnr容器来构造一个stack
template <class Alloc> //可以指定内存分配器
stack (container_type&& ctnr, const Alloc& alloc);
//复制stack构造
template <class Alloc> //可以指定内存分配器
stack (const stack& x, const Alloc& alloc);
//移动stack构造
template <class Alloc> //可以指定内存分配器
stack (stack&& x, const Alloc& alloc);
示例:
// constructing stacks
#include <iostream> // std::cout
#include <stack> // std::stack
#include <vector> // std::vector
#include <deque> // std::deque
int main ()
{
std::deque<int> mydeque (3,100); // deque with 3 elements
std::vector<int> myvector (2,200); // vector with 2 elements
std::stack<int> first; // empty stack
std::stack<int> second (mydeque); //用deque构造一个栈(size=3)
std::stack<int,std::vector<int> > third;// 指明用vector实现一个栈(存放int),空栈size=0
std::stack<int,std::vector<int> > fourth (myvector);//用myvector构造一个栈,size=2
std::cout << "size of first: " << first.size() << '\n';
std::cout << "size of second: " << second.size() << '\n';
std::cout << "size of third: " << third.size() << '\n';
std::cout << "size of fourth: " << fourth.size() << '\n';
return 0;
}
入栈
- push:在栈顶增加元素
void push (const value_type& val);
void push (value_type&& val);
出栈
- top:返回栈顶元素的引用
reference& top();
const_reference& top() const;
- pop: 移除栈顶元素
void pop();
其他
- emplace:入栈一个元素,只是这个元素值可以是调用模板类型T的构造函数生成的,然后入栈。
template <class... Args> void emplace (Args&&... args);
// stack::emplace
#include <iostream> // std::cin, std::cout
#include <stack> // std::stack
#include <string> // std::string, std::getline(string)
#include<utility>
int main ()
{
std::stack<std::pair<int,std::string>> mystack;
mystack.push(std::make_pair(0,"Zero"));//push的形参必须是已经构造的pair对象
mystack.emplace(1,"First sentence");//emplace则可以根据形参自动构造pair对象,然后入栈
mystack.emplace (2,"Second sentence");
std::cout << "mystack contains:\n";
while (!mystack.empty())
{
std::cout << mystack.top().first<<' '<<mystack.top().second << '\n';
mystack.pop();
}
return 0;
}
- empty:栈为空则返回true
bool empty() const;
- swap:交换自身和参数x的内容
void swap (stack& x) noexcept(/*see below*/);
- size:返回栈中元素数目
size_type size() const;
queue
参考:http://www.cplusplus.com/reference/queue/queue/
queue是一种先进先出的数据结构,它有两个出口,允许新增元素、移除元素、从最底端加入元素、取出最顶端元素,queue不提供遍历功能,所以没有迭代器。
类模板声明
template <class T, class Container = deque<T> > class queue;
头文件
#include<queue>
初始化
//注意:下面所有的ctnr容器都是跟queue模板声明中的class Container=deque<T>对应的,默认是deque<T>
//所以默认情况下,下面的ctnr都是deque容器
//复制ctnr容器来构造一个queue
explicit queue (const container_type& ctnr);
//移动ctnr容器来构造一个queue
explicit queue (container_type&& ctnr = container_type());
//默认无参构造
template <class Alloc> //可以自定以内存分配器
explicit queue (const Alloc& alloc);
//复制ctnr容器来构造一个queue
template <class Alloc> //可以自定以内存分配器
queue (const container_type& ctnr, const Alloc& alloc);
//移动ctnr容器来构造一个queue
template <class Alloc> //可以自定以内存分配器
queue (container_type&& ctnr, const Alloc& alloc);
//复制queue来构造一个queue
template <class Alloc>
queue (const queue& x, const Alloc& alloc);
//移动queue来构造一个queue
template <class Alloc>
queue (queue&& x, const Alloc& alloc);
// constructing queues
#include <iostream> // std::cout
#include <deque> // std::deque
#include <list> // std::list
#include <queue> // std::queue
int main ()
{
std::deque<int> mydeck (3,100); // deque with 3 elements
std::list<int> mylist (2,200); // list with 2 elements
std::queue<int> first; // empty queue
std::queue<int> second (mydeck); // queue initialized to copy of deque
std::queue<int,std::list<int> > third; // empty queue with list as underlying container
std::queue<int,std::list<int> > fourth (mylist);
std::cout << "size of first: " << first.size() << '\n';
std::cout << "size of second: " << second.size() << '\n';
std::cout << "size of third: " << third.size() << '\n';
std::cout << "size of fourth: " << fourth.size() << '\n';
return 0;
}
入队
- push:队尾入队一个元素
void push (const value_type& val);
void push (value_type&& val);
- emplace:队尾入队一个元素,这个元素被它自身的构造函数构造。一般用于复合类型数据操作
template <class... Args> void emplace (Args&&... args);
// queue::emplace
#include <iostream> // std::cin, std::cout
#include <queue> // std::queue
#include <string> // std::string, std::getline(string)
#include<utility>
int main ()
{
std::queue<std::pair<int,std::string>> myqueue;
myqueue.push(std::make_pair(0,"Zero"));//push的形参必须是已经构造好的pair对象
myqueue.emplace (1,"First sentence");//emplace则可以根据形参去调用类型的构造函数构造pair对象
myqueue.emplace (2,"Second sentence");
std::cout << "myqueue contains:\n";
while (!myqueue.empty())
{
std::cout << myqueue.front().first<<' '<<myqueue.front().second << '\n';
myqueue.pop();
}
return 0;
}
队头&&队尾
- front:返回队首元素的引用
reference& front();
const_reference& front() const;
- back:返回队尾元素的引用
reference& back();
const_reference& back() const;
出队
先调用 front()函数获取队头元素,然后再调用pop()函数弹出队头元素
- pop:队首元素出队
void pop();
其他
- empty:queue为空则返回true
bool empty() const;
- size:返回queue中的元素个数
size_type size() const;
- swap:交换自身和参数x的内容
void swap (queue& x) noexcept;
priority_queue
参考:http://www.cplusplus.com/reference/queue/priority_queue/
大顶堆
类的模板声明
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
默认是大顶堆,注意,如果不使用默认的模板参数,则必须给出三个类型来实例化模板
比如,我想定义一个小顶堆
priority_queue<int,vector<int>,greater<int>> least;
而不能像下面这样
priority_queue<int,greater<int>> least;//记住这是错误的
头文件
#include <queue>
初始化
//注意:下面所有的ctnr容器都是跟priority_queue模板声明中的class Container = vector<T>对应的,默认是vector<T>
//所以默认情况下,下面的ctnr都是vector容器
//复制ctnr容器来构造一个priority_queue
priority_queue (const Compare& comp, const Container& ctnr);
//根据迭代器范围[first,last)来构造一个priority_queue
template <class InputIterator>
priority_queue (InputIterator first, InputIterator last,
const Compare& comp, const Container& ctnr);
//默认无参构造
//comp是默认的 less<typename Container::value_type>,就是大顶堆
explicit priority_queue (const Compare& comp = Compare(),
Container&& ctnr = Container());
//根据迭代器范围[first,last)来构造一个priority_queue
template <class InputIterator>
priority_queue (InputIterator first, InputIterator last,
const Compare& comp, Container&& ctnr = Container());
//默认无参构造
template <class Alloc>
explicit priority_queue (const Alloc& alloc);//自定义内存分配器
template <class Alloc>
priority_queue (const Compare& comp, const Alloc& alloc);//自定义比较器和内存分配器
//根据容器ctnr构造
template <class Alloc> //自定义比较器和内存分配器
priority_queue (const Compare& comp, const Container& ctnr,const Alloc& alloc);
//根据容器ctnr构造,移动语义
template <class Alloc> //自定义比较器和内存分配器
priority_queue (const Compare& comp, Container&& ctnr,const Alloc& alloc);
//根据priority_queue复制构造,必须显式提供内存分配器alloc
template <class Alloc>
priority_queue (const priority_queue& x, const Alloc& alloc);
//根据priority_queue复制构造,移动语义,必须显式提供内存分配器alloc
template <class Alloc>
priority_queue (priority_queue&& x, const Alloc& alloc);
示例
// constructing priority queues
#include <iostream> // std::cout
#include <queue> // std::priority_queue
#include <vector> // std::vector
#include <functional> // std::greater
class mycomparison
{
bool reverse;
public:
mycomparison(const bool& revparam=false)
{reverse=revparam;}
bool operator() (const int& lhs, const int&rhs) const
{
if (reverse) return (lhs>rhs);
else return (lhs<rhs);
}
};
int main ()
{
int myints[]= {10,60,50,20};
std::priority_queue<int> first;
std::priority_queue<int> second (myints,myints+4);//默认std::less<int> 大顶堆
//注意这里更改默认的比较器时,必须显示给定全部三个模板类型
//因为比较器是第三个模板类型,不默认的话,前两个都得依次给出
// std::priority_queue<int, std::greater<int> > third (myints,myints+4);//注意这是错误的
std::priority_queue<int, std::vector<int>, std::greater<int> > third (myints,myints+4);//自定义std::greater<int>> 小顶堆
int size=second.size();
for(int i=0;i<size;i++){
std::cout<<second.top()<<" ";
second.pop();
}
std::cout<<std::endl;
for(int i=0;i<size;i++){
std::cout<<third.top()<<" ";
third.pop();
}
// using mycomparison:
typedef std::priority_queue<int,std::vector<int>,mycomparison> mypq_type;
mypq_type fourth; // less-than comparison,自定义比较器的大顶堆
mypq_type fifth (mycomparison(true)); // greater-than comparison,自定义比较器的小顶堆
system("pause");
return 0;
}
自定义类型的priority_queue的详细用法
参考priority_queue的用法
要点如下:
- 重载比较运算符,然后包装成比较器
- 在自定义类型中重载bool operator<(…)函数,然后使用std::less<自定义类型>,大顶堆
- 在自定义类型中重载bool operator>(…)函数,然后使用std::greater<自定义类型>,小顶堆
- 自定义定义仿函数(必须是仿函数,不能是普通函数)
class{
public:
bool operator()(自定义类型1,自定义类型2){
//比较逻辑
}
}
至于是大顶堆还是小顶堆,就看你实现逻辑了。如果函数内部是第一个参数小于第二个参数,返回true,则是大顶堆;如果函数内部是第一个参数大于第二个参数,返回true,则是小顶堆;
例题:
23. 合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
思路: 使用优先队列合并
我们需要维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。
先看看自定义仿函数的解法
class Solution {
public:
class cmp{
public:
bool operator()(ListNode* a,ListNode* b){
return a->val > b->val;
}
};
//小顶堆
priority_queue<ListNode*,vector<ListNode*>,cmp> q;
ListNode* mergeKLists(vector<ListNode*>& lists) {
int N=lists.size();
if(N==0) return nullptr;
if(N==1) return lists[0];
for(auto i:lists){
if(i)
q.push(i);
}
ListNode head,*tail=&head;;
while(!q.empty()){
ListNode* t=q.top();
tail->next=t;
tail=tail->next;
q.pop();
if(t->next)
q.push(t->next);
}
return head.next;
}
};
再看看在结构体内部重载bool operator<()函数的做法
class Solution {
public:
struct Status {
int val;
ListNode *ptr;
bool operator < (const Status &rhs) const {
return val > rhs.val;
}
};
priority_queue <Status> q;
ListNode* mergeKLists(vector<ListNode*>& lists) {
for (auto node: lists) {
if (node) q.push({node->val, node});
}
ListNode head, *tail = &head;
while (!q.empty()) {
auto f = q.top(); q.pop();
tail->next = f.ptr;
tail = tail->next;
if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});
}
return head.next;
}
};
入队
- push:入队一个元素
void push (const value_type& val);
void push (value_type&& val);
- emplace:入队一个元素,这个元素被它自身的构造函数构造。一般用于复合类型数据操作.
template <class... Args> void emplace (Args&&... args);
出队
- top:返回队首元素的引用
const_reference top() const;
- pop:队首元素出队
void pop();
删除
- 直接用空的队列对象赋值
priority_queue<int> queue_node;
queue_node.push(1);
queue_node.push(2);
cout << "empty:" << queue_node.empty();
queue_node = {};
cout << "empty:" << queue_node.empty();
- 使用swap
priority_queue<int> queue_node;
queue_node.push(1);
queue_node.push(2);
cout << "empty:" << queue_node.empty();
// 定义一个空的 priority_queue 对象
priority_queue<int> null_queue;
queue_node.swap(null_queue);
cout << "empty:" << queue_node.empty();
其他
- empty:prioriity_queue为空则返回true
bool empty() const;
- size:返回prioriity_queue中的元素个数
size_type size() const;
- swap:交换自身和参数x的内容
void swap (priority_queue& x) noexcept;
优先队列解决Top k问题
//海量数据找出Top k个元素
//1.若是找最大的k个元素,则建立一个大小为k的小顶堆,然后遍历输入数据
//若当前数大于堆顶元素,则删除堆顶元素,当前元素入堆
//若当前数小于堆顶元素,则跳过,直接遍历下一个
//示例
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
//注意这里更改默认的比较器时,必须显示给定全部三个模板类型
//因为比较器是第三个模板类型,不默认的话,前两个都得依次给出
// std::priority_queue<int, std::greater<int>> BiggestNumbers;//注意这是错误的
priority_queue<int,vector<int>,greater<int>> BiggestNumbers;//保存结果的小顶堆
void getBiggetNumbers(const vector<int>& data,priority_queue<int,vector<int>,greater<int>>& BiggestNumbers,int k){
//因为BiggestNumbers是全局变量,所以使用前最好清空一下
//priority_queue没有clear(),所以需要通过swap函数来实现clear()的功能
priority_queue<int,vector<int>,greater<int>>().swap(BiggestNumbers);//构建一个空的临时对象,然后交换
if(data.size()<1||k<1||data.size()<k)
return ;
//
for(int i=0;i<data.size();i++){
//先把小顶堆填满
if(i<k)
BiggestNumbers.push(data[i]);
//后面每次都与小顶堆的堆顶元素比较,大于,则删除堆顶元素,自己入堆
else{
if(data[i]>BiggestNumbers.top())
{
BiggestNumbers.pop();
BiggestNumbers.push(data[i]);
}
}
}
}
int main()
{
vector<int> data{1,3,2,4,2,5,7,5,8,4,2,7,746,7,5,3,63,45,6,63,63,56,4,7};
getBiggetNumbers(data,BiggestNumbers,6);
int size = BiggestNumbers.size();
for(int i=0;i<size;i++)
{
cout<<BiggestNumbers.top()<<" ";
BiggestNumbers.pop();
}
system("pause");
return 0;
}