栈,队列,优先队列详解

栈,队列,优先队列详解

  • 栈的概念,应用与实现
    • 队列的概念,应用与实现
      • 优先队列的概念应用与实现

栈的概念,应用与实现

一. 栈的概念
首先栈是一个后进先出的数据结构,对于栈来说,只有一种插入和删除的方式就是通过头来实现,也就是从头压入,从头弹出。当通过STL调用栈的时候需要使用头文件 #include

二. 栈的应用
对于栈来说我们都比较熟悉的几个函数分别是
1.push()插入函数
2.pop()弹出函数
3.top()返回栈顶函数
4.size()返回栈中元素个数函数
5.emoty()判断栈是否为空函数
具体应用实现如下:
栈,队列,优先队列详解_第1张图片
三. 栈的底层实现
在STL中栈和vector,string这类容器是不一样的,vector和string其实本质上就是数组和字符串,所以可以通过迭代器来实现,而栈本身不是一个容器,而是要使用其他容器来实现的,比如我们可以通过vector来实现栈,如下:
栈,队列,优先队列详解_第2张图片
此处定义的泛型中的Container表示的是一个容器适配器,这里也给了他一个缺省值,所以这里我们Container就代表vector类型,所以可以看到我们定义了一个vector类型的变量_con。并且通过vector实现了栈,比如插入操作,直接使用vector中的插入函数,比如pop()操作,直接将vector中尾部元素删除此时也满足了栈的后进先出,这样就可以完美的通过vector来实现栈的所有功能。当然这个这个容器适配器的种类不是唯一的,我们也可以通过deque双端队列或者list链表来实现栈。

队列的概念,应用与实现

一. 队列的概念
首先队列是一种先进先出的数据结构,和栈不同的是,他可以在尾部插入并在头部弹出,和栈一样的是,队列也不是一种容器,也是需要通过其他容器来实现的。当通过STL调用队列的时候需要使用头文件#include

二. 队列的应用
和上面的栈大同小异,队列也有这么几个函数分别是
1.push插入函数
2.pop弹出函数
3.front取队头数据
4.back取队尾数据
5.size取队列中元素个数
6.empty判断队列是否是空
具体应用实现如下:
栈,队列,优先队列详解_第3张图片
三. 队列的底层实现
上面我们说了,队列和栈一样不是容器,所以底层实现也要使用其他容器来实现,具体如下:
栈,队列,优先队列详解_第4张图片
此处我们是通过容器deque(双端队列)来实现队列的,因为队列的删除与插入都是在首尾的,而deque容器正好也有头插和尾插的函数,所以用此容器来实现再合适不过了。如这里的push函数就在尾部插入一个数据,pop函数就是将首部的数据删除掉也就是pop_front(),如此类推。

优先队列的概念应用与实现

一. 优先队列的概念
不要看优先队列和队列都有一个队列这个词,但是这两个根本就不是一个东西,我们上边介绍的队列是一种先进先出的数据结构,而优先队列是没有插入顺序的,你可以随便插入,而在弹出的时候,会返回优先级最高的元素,如,要是把1 2 3 4 这四个元素插入到优先队列中,那么因为4这个元素的优先级最高,所以会返回4这个元素,当然优先级的高低是可以由人为调整的。优先队列本质上就是一个堆。

二. 优先队列的应用
上面说过,优先队列的本质其实就是一个堆,那么当优先队列返回的时候就会返回优先级最高的元素也就是堆顶元素,所以优先队列的返回函数就是top()函数,其他的函数和队列中没有什么差别。
具体应用实现如下:
栈,队列,优先队列详解_第5张图片
上面我们先定义了一个小根堆,小根堆的意思就是将优先队列中的优先级变成以小的作为优先级大的元素,也就是元素的值越小,优先级越高,有点像Linux中的优先级。之后我们向这个优先队列中插入四个数字,之后我们对优先队列中的元素进行打印,就会显示出数字从小到大进行排列输出出来。

三. 优先队列的底层实现
之前我们说过,优先队列本质上其实就是一个堆,所以我们就通过实现堆排序的方式来实现优先队列,这里优先队列和上面的队列和栈是一样的,都不是容器,都是需要通过容器来实现的。这里我们使用vector来实现优先队列。和之前不同的是,这里优先队列会比上面的泛型定义中多出一个参数,这个参数就是用来判断我们的优先级是以那种方式实现的,也就是类似一个判定器,这里对于优先队列来说有两种优先级,一种是以小为优先级大的,一种是以大的作为优先级大的。 准确的说,优先队列在这里使用的是仿函数,那么什么是仿函数呢?看名字我们就能看出来,仿函数就是仿造函数,本质上并不是函数,其实就是函数对象,也就是当前类可以像函数一样去使用,这里我们就用到了两个仿函数分别为: less 和 greater,具体实现如下:
栈,队列,优先队列详解_第6张图片
此处我们定义两个类,这两个类中只有一个对括号的重载函数,如果是less那么当前定义的就是以大优先的优先队列,如果是greater,那么定义就是以小优先的优先队列。

上面我们说这里的优先队列是将优先级最大的放到最上面,那么如果我们将最上面的元素弹出的话,那么我们还要重新进行查找最大的值作为队头元素,这里的操作会不会让你想到之前学过的堆排序的操作呢!当队头元素删除的时候我们就将队头元素和队尾元素的值进行交换,然后我们将队尾元素进行删除,之后将第一个元素向下调整就可以重新找到最大的值来作为队头了,所以这里优先队列弹出队首元素䣌操作必须需要堆排序中的向下调整,所以我就先将向下调整操作写出来。
栈,队列,优先队列详解_第7张图片
和上面一样我们在进行插入操作的时候我们可以直接对当前元素进行上调操作,这样就可以省去建堆的代码,当我们将每个插入的元素进行上调操作,那么当我们插入完最后一个元素的时候,数组的第一个元素就是优先级最大的元素了,所以这里我们先实现一下上调操作。
栈,队列,优先队列详解_第8张图片
有了这上调和下调操作我们就可以实现push插入操作和pop弹出操作了,当push插入操作的时候我们就正常将元素push_back进vector中,并将容器进行上调操作,将优先级最大的元素放到最上面,所以我们可以实现出push插入操作。
在这里插入图片描述
和push操作同理,当我们将优先级第一的元素删除的时候我们就要在剩余元素中选出下一个优先级第一的元素,这里我们就要使用下调操作,将第一个元素和最后一个元素的值交换之后将容器进行pop_back操作,然后再对第一个元素进行下调操作,具体操作如下:
栈,队列,优先队列详解_第9张图片
剩下的操作就比较普通没有什么特殊的部分了,我们就直接将所有的代码给出来,具体代码如下:
栈,队列,优先队列详解_第10张图片
此处使用我们自己创建的域中实现的优先队列,得到以下结果:
栈,队列,优先队列详解_第11张图片
以上就是栈,队列和优先队列的具体详解。

你可能感兴趣的:(it,数据结构,stl,c++)