STL源码笔记(15)—堆和优先级队列(二)

STL源码笔记(15)—堆和优先级队列

优先级队列的源码实现基于heap的操作,底层容器默认是vector。

优先级队列简介

优先级队列跟队列类似,一端插入一端删除,不同的是,优先级队列的元素入队后会根据其优先级进行调整,默认情况下优先级高的将优先出队,在SGI STL中,优先级队列的功能保证由heap实现:stl_heap.h中,heap的分析见:STL堆源码分析

优先级队列构造函数

默认情况下,优先级队列使用vector作为底层容器,使用less作为比较函数,其在源码中的定义声明如下:

template <class _Tp,
          class _Sequence __STL_DEPENDENT_DEFAULT_TMPL(vector<_Tp>),
          class _Compare
          __STL_DEPENDENT_DEFAULT_TMPL(less<typename _Sequence::value_type>) >
class priority_queue {
//1.default construct
 priority_queue() : c() {}
 //2.以特定比较函数构造,空的容器
  explicit priority_queue(const _Compare& __x) :  c(), comp(__x) {}
  //3.以特定比较函数和特定容器构造
  priority_queue(const _Compare& __x, const _Sequence& __s)
    : c(__s), comp(__x)
    { make_heap(c.begin(), c.end(), comp); }//这里make_heap类似于堆排序中的建堆操作
};

根据上述定义,如果要使用其他的比较函数,则必须进行如下声明:

class mycmp1
{
public:
    mycmp1(){}
    bool operator()(const int &a, const int &b)
    {
        return a < b;
    }
};
int main()
{
    vector<int>a = { 1, 2, 3 };
    priority_queue<int,vector<int>, mycmp1>pq;//方式1
    priority_queue<int,vector<int>, mycmp1>pq1(mycmp1::mycmp1());//方式2
    priority_queue<int,vector<int>, mycmp1>pq2(mycmp1::mycmp1(),a);//方式3
}

上述声明过程模板实参必不可少。

优先级队列操作

empty

Test whether container is empty (public member function )

size

Return size (public member function )

top

Access top element (public member function )

push

Insert element (public member function )

pop

Remove top element (public member function )

有了heap的操作,上述实现就十分简单了:

bool empty() const { return c.empty(); }//直接调用底层容器
size_type size() const { return c.size(); }//直接调用底层容器
const_reference top() const { return c.front(); }//直接调用底层容器

void push(const value_type& __x) {
    __STL_TRY {
      c.push_back(__x); //先在尾部插入元素
      push_heap(c.begin(), c.end(), comp);//再对该元素进行入堆操作
    }
    __STL_UNWIND(c.clear());
  }
  void pop() {
    __STL_TRY {
      pop_heap(c.begin(), c.end(), comp);//出堆只是将堆顶元素放到最后
      c.pop_back();//将最后的原堆顶元素弹出
    }
    __STL_UNWIND(c.clear());
  }
};

优先级队列应用

前两天刷leetcode就有碰到用优先级队列解决的问题:LeetCode347—Top K Frequent Elements

另外,如果我们要求说是优先级队列要按class中的某个成员变量来进行优先级判定,例如,经典的就是学生3门课成绩优先看数学。

class score
{
    int math;
    int chinese;
    int english;
public:
    score(){}
    void print()
    {
        cout << math << " " << chinese << " " << english << " " << endl;
    }
    score(int a, int b, int c)
    {
        math = a;
        chinese = b;
        english = c;
    }
    bool cmp2(const score&sc)
    {
        return math < sc.math;
    }
};
class mycmp2
{
public:
    mycmp2(){}
    bool operator() (score&sc1, score&sc2)
    {
        return sc1.cmp2(sc2);
    }
};
int main()
{
    vector<score>vec;
    score a(2,0,0);
    score b(1, 0, 0);
    score c(3,0,0);
    vec.push_back(a);
    vec.push_back(b);
    vec.push_back(c);
    priority_queue<score, vector<score>, mycmp2>pq(mycmp2::mycmp2(),vec);
    while (!pq.empty())
    {
        pq.top().print();
        pq.pop();
    }
    system("pause");
    return 0;
}

结果显示为:

时间: 2024-07-29 19:34:49

STL源码笔记(15)—堆和优先级队列(二)的相关文章

STL源码笔记(14)—堆和优先级队列(一)

STL源码笔记(14)-堆和优先级队列 priority_queue是拥有权值观念的queue,跟queue类似,其只能在一端push,一端pop,不同的是,每次push元素之后再容器内部元素将按照一定次序排列,使得pop得到的元素始终是当前权值的极大值. 很显然,满足这个条件就需要某些机制了,缺省情况下使用max-heap大顶堆来实现,联想堆排序的实现,使用大顶完成序列从小到大的排序,过程大概是: 把堆的根元素(堆中极大值)交换到最后 堆的长度减1 这样每次取出堆中的极大值完成排序,刚好与优先

STL源码笔记(12)—序列式容器之deque(二)

STL源码笔记(12)-序列式容器之deque(二) 再谈deque数据结构 我们知道deque是通过map管理很多个互相独立连续空间,由于对deque_iterator的特殊设计,使得在使用的时候就好像连续一样.有了deque_iterator的基础(例如重载的操作符等),对于我们实现容器的一些方法就十分方便了.与vector一样,deque也维护一个start,和finish两个迭代器,start指向容器中的一个元素,finish指向最后一个元素的后一个位置(前闭后开),从微观上讲,star

STL源码笔记(16)—单链表slist

STL单链表slist简介 概述 slist(Single linked list)顾名思义,是一个单向链表,这个容器并不在标准规格之内,在我几年的代码学习生涯中也是第一次听说,既然侯老师的书中提到了,那也还是学习一蛤. slist与list的主要差别是,前者的迭代器属于单向的Forward Iterator(可读写),后者的迭代器属于双向的Bidirectional Iterator(可以双向读写).看起来slist的功能应该会不如list,但由于其单向链表的实现,其消耗的空间更小,某些操作更

STL源码笔记(18)—平衡二叉树AVL(C++封装+模板)

AVLTree平衡二叉树 在几年前刚学数据结构时,AVL-Tree只是一个仅仅需要掌握其概念的东西,今非昔比,借看STL源码剖析的契机希望从代码层面将其拿下. 1.简介 二叉查找树给我们带来了很多方便,但是由于其在有序序列插入时就会退化成单链表(时间复杂度退化成 O(n)),AVL-tree就克服了上述困难.AVL-tree是一个"加上了平衡条件的"二叉搜索树,平衡条件确保整棵树的深度为O(log n). AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差

STL源码笔记(17)—二叉排序树BST(C++封装)

二叉排序树BST STL中还有一类非常重要的容器,就是关联容器,比如map啊set啊等等,这些容器说实话,在应用层上还不能完全得心应手(比如几种容器效率的考虑等等),更别说源码了,因此这一部分打算稳扎稳打,好好做做笔记研究一番. 说到关联容器,我们想到了什么AVL树,红黑树等等,但大多时候我们仅仅局限于知道其名字,或者知道其概念,俗话说"talk is cheap,show me the code",因此,我打算从他们的祖爷爷二叉排序树开始下手.(其实,侯老师的书上也是这么安排的哈)

通读《STL源码剖析》之后的一点读书笔记

[QQ群: 189191838,对算法和C++感兴趣可以进来] 直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adaptors).算法(algorithms).仿函数(functors)六个部分. 迭代器和泛型编程的思想在这里几乎用到了极致.模板或者泛型编程其实就是算法实现时不指定具体类型,而由调用的时候指定类型,进行特化.在STL中,迭代器保证了ST

《STL源码剖析》---stl_iterator.h阅读笔记

STL设计的中心思想是将容器(container)和算法(algorithm)分开,迭代器是容器(container)和算法(algorithm)之间的桥梁. 迭代器可以如下定义:提供一种方法,能够依序寻访某个容器内的所有元素,而又无需暴露该容器的内部表达方式. 在阅读代码之前,要先了解一个新概念:Traits编程技法 template <class T> struct MyIter { typedef T value_type //内嵌型别声明 T *ptr; MyIter(T *p = 0

《STL源码剖析》---stl_alloc.h阅读笔记

这一节是讲空间的配置与释放,但不涉及对象的构造和析构,只是讲解对象构造前空前的申请以及对象析构后空间怎么释放. SGI版本的STL对空间的的申请和释放做了如下考虑: 1.向堆申请空间 2.考虑了多线程.但是这节目的只是讲解空间配置与释放,因此忽略了多线程,集中学习空间的申请和释放. 3.内存不足时的应变措施 4.考虑到了内存碎片的问题.多次申请释放小块内存可能会造成内存碎片. 在C++中,内存的申请和释放是通过operator new函数和operator delete函数,这两个函数相当于C语

《STL源码剖析》---stl_heap.h阅读笔记

Heap堆是常用的数据结构,Heap中也可以存放元素.但是STL中并没有提供Heap容器,只是提供了关于Heap操作的算法.只要支持RandomAccessIterator的容器都可以作为Heap容器. Heap分为max heap和min heap,max heap中每次取出的结点时heap结构中值最大的结点,min heap中每次取出的结点时heap结构中值最小的结点. 在实际应用中,经常用vector作为heap容器,heap经常作为priority queue.对于二叉堆,这里有描述ht