C++STL-priority_queue的实现

大家好!这篇文章,主要讲解一下这个优先级队列,还包含了仿函数等等的知识。希望大家能够一起加油!!!
C++STL-priority_queue的实现_第1张图片

文章目录

  • 1. priority_queue的实现
    • 1.1 push函数
    • 1.2 pop函数
    • 1.3 top函数和empty函数
  • 2. 仿函数
    • 2.1 仿函数的由来和定义
    • 2.2 改造priority_queue
    • 2.3 sort的仿函数
    • 2.4 什么时候要写仿函数呢
  • 3. priority_queue的构造

1. priority_queue的实现

它在STL中是这个样子:
C++STL-priority_queue的实现_第2张图片
我们先不看仿函数,先把框架实现一下:
C++STL-priority_queue的实现_第3张图片
它的成员函数有这些,我们一个一个来实现。

1.1 push函数

C++STL-priority_queue的实现_第4张图片
我们这里把数据插入到容器里了,但还是不行。因为它还不是一个大堆。我们需要写一个向上调整来创建一个大堆。大堆是如何创建的呢?不懂的可以看这里:堆的创建
在这里插入图片描述
实现如下:
C++STL-priority_queue的实现_第5张图片
这样,每当我们插入一个数据时,它会向上调整,形成一个大堆。

1.2 pop函数

pop函数其实是删除堆的顶部元素。那么堆的删除是如何做的,我们可以看这里:堆的删除
C++STL-priority_queue的实现_第6张图片
实现如下:
C++STL-priority_queue的实现_第7张图片

1.3 top函数和empty函数

C++STL-priority_queue的实现_第8张图片
这里使用引用可能里面存的是像string这样的类,拷贝构造的代码比较大。加const是因为我们不能改变里面的元素,防止它不是一个堆了。
C++STL-priority_queue的实现_第9张图片
这两个函数比较简单,就不多说了。

我们来测试一下写的对不对:
C++STL-priority_queue的实现_第10张图片
我们可以看到是没有什么太大的问题。这里我们给它写死了,如果我们想升序排列,就没有办法了。这时,我们需要用仿函数的知识。

2. 仿函数

2.1 仿函数的由来和定义

我们知道,在C语言中我们使用函数指针的时候会很麻烦。而仿函数就是解决这个问题。
定义:仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符
举个例子:
C++STL-priority_queue的实现_第11张图片
我们在这里写了一个less类,里面重载了()运算符。所以我们就可以这样去使用:
C++STL-priority_queue的实现_第12张图片
这里我们用这个less类来定义一个对象,然后用这个对象来调用重载的()运算符。从这里我们可以看到它的调用方式和函数非常的相似。这样我们也可以来比较大小。如果我们想比较不同类型的,我们可以加上模板。
C++STL-priority_queue的实现_第13张图片
有比小的,也会有比较大的。
C++STL-priority_queue的实现_第14张图片
那么这样的话,我们就可以把这个设成我们priority_queue的模板参数。当传不同的仿函数时,可以调用不同的方法。

2.2 改造priority_queue

在这里插入图片描述
然后我们可以这样来写:
C++STL-priority_queue的实现_第15张图片
这样默认的情况下,传的是less这个类模板,父亲比孩子小交换,也就是创建的是大堆。如果我们给它传greater类模板,父亲比孩子大交换,创建的就是小堆。
C++STL-priority_queue的实现_第16张图片
向下调整也是一样的道理。现在我们就来测试一下这样写行不行:
C++STL-priority_queue的实现_第17张图片
默认情况下是大堆,没有问题。
C++STL-priority_queue的实现_第18张图片
小堆也没有问题。

2.3 sort的仿函数

C++STL-priority_queue的实现_第19张图片
它和priority_queue的区别在priority_queue是在模板中传类型,而sort是在函数中传递这个对象
举个例子:
C++STL-priority_queue的实现_第20张图片
其实在这里,我们也不是说必须要传迭代器才能排序。我们也可以传普通的数组。
C++STL-priority_queue的实现_第21张图片
因为指向数组的原生指针,本身就是天然的迭代器

2.4 什么时候要写仿函数呢

看下面的例子:
C++STL-priority_queue的实现_第22张图片
对于自定义类型,我们把它们进行比较,不能直接比,我们需要自己写比较函数。
C++STL-priority_queue的实现_第23张图片
这里我们用的是以价格默认升序排序,但是如果我们现在想以销售的数量为升序排,该怎么办呢?它就不能灵活的排了,此时我们就需要写仿函数。
C++STL-priority_queue的实现_第24张图片
这样,我们就可以灵活的去比较自定义类型的各个成员变量了。

3. priority_queue的构造

我们来看一下库里的构造是如何写的:
C++STL-priority_queue的实现_第25张图片
我们先看第一个。其实在C++里,我们需要兼容C语言,也就是需要兼容函数指针。
举个例子:
C++STL-priority_queue的实现_第26张图片
这里我们写了一个函数,如果用C语言的话,我们需要用函数指针。因为priority_queue传的是类型。所以应该这样:
C++STL-priority_queue的实现_第27张图片
那么这里模板的话:
C++STL-priority_queue的实现_第28张图片
我们只知道指针的类型,不知道指针指向谁?只是定义了一个野指针,无法使用。所以在构造的时候,我们加了一个这样东西:
在这里插入图片描述
怎么写的呢?我们来看:
C++STL-priority_queue的实现_第29张图片
C++STL-priority_queue的实现_第30张图片
我们在这里加了一个成员变量。如果传的是less这种类模板,那么这个成员变量就会拷贝成这个对象,然后去调用operator()。如果传的是一个函数指针,也会定义一个对象。在C++中对内置类型升级了。
C++STL-priority_queue的实现_第31张图片
C++STL-priority_queue的实现_第32张图片
如果传的是函数指针,初始化后是一个空指针,还是不能使用。所以我们在使用的时候,还要传。
C++STL-priority_queue的实现_第33张图片
这样在初始化时就知道函数指针指向的是谁了。

然后,我们再来谈一下第二个构造
在这里插入图片描述
C++STL-priority_queue的实现_第34张图片
在一些TOP-K问题可以使用。

你可能感兴趣的:(C++,c++,STL)