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的用法

要点如下:

  1. 重载比较运算符,然后包装成比较器
  • 在自定义类型中重载bool operator<(…)函数,然后使用std::less<自定义类型>,大顶堆
  • 在自定义类型中重载bool operator>(…)函数,然后使用std::greater<自定义类型>,小顶堆
  1. 自定义定义仿函数(必须是仿函数,不能是普通函数)
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;
}

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值