目录
1,优先队列的概念
队列的概念相信大家都有接触过,先进先出,后进后出,这个规则相信大家都不陌生,这是普通队列的出入规则,但是什么是优先队列呢?
优先队列就是根据优先级来确定出入的顺序,普通队列是根据时间来决定出入顺序。优先队列有点像计算机处理器的时间调度。
2,为什么要执行优先队列?
为什么要使用优先队列呢?优先队列在现实生活中有哪些应用呢?
为什么要使用有限队列,当然是看重了优先队列的特性:根据优先级来确定出入顺序,当然这个过程是动态的,实时的。在当前队列的当前时间,让优先级高的先出。记住这个过程,是动态的,实时的。
优先队列在生活中的应用就太广泛了,讲个宽泛的例子,医院里的急诊室大家都知道,它就是一个优先级的应用,如果一个重伤病人(优先级高)和一个轻伤的病人在一起,即使这个轻伤的病人等了很久,医院也会先治疗重伤的病人。
3,预先队列的主要操作
优先队列的主要操作:入队和出队
4,如何实现优先队列
优先队列的实现方式主要有三种:普通数组,顺序数组,堆
下图是分别使用这三种数据结构实现优先队列的时间复杂度。可以看出,使用堆来实现优先队列,在时间复杂度上要优于其他两种。
5,用堆实现优先队列
通过上一小节的学习,我们都知道了使用堆来实现优先队列在时间复杂度上要优于其他实现方式,那么用堆实现优先队列在各种情况下的时间复杂度具体又是如何呢?
具体如图所示:
6,堆的基本存储
既然确定了使用堆来实现优先队列,那么堆是如何存储数据的呢?
堆的逻辑结构是一颗完全二叉树,但物理结构是顺序表(一维数组)。同时,此处的堆不要与JAVA内存分配中的堆内存混淆。这里讨论的是数据结构中的堆。
由于堆从逻辑上看是一颗完全二叉树,因此可以按照层序遍历的顺序将元素放入一维数组中。
什么是二叉树?
二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。
什么是完全二叉树?
叶子只能出现在最下面的二层
最下层的叶子一定集中在左部的连续位置
倒数第二层 若有叶子结点 一定在右部连续位置
如果结点的度为1 ,则该结点只有左孩子
同样结点的二叉树,完全二叉树的深度最小
二叉堆是一个完全二叉树,所以大家必须掌握完全二叉树的原理以及实现。
最大堆?所有子节点都小于自己本身
最小堆?所有子节点都大于自己本身
7,使用数组实现二叉堆
如果把二叉堆中的每个节点都打上一个数字标记,就会发现如下图中的规律。
注意为了方便,数组的元素存放从索引 1 处开始(不是0)。采用数组来存放就很容易地找到某个结点 i 的双亲结点(i/2),孩子结点(左孩子:2i,右孩子:2i+1)
8,堆的基本代码实现。
这里仅仅只是实现堆的基础结构,不包含任何操作。堆的具体操作会在下一节中来进行学习。
package com.smarking.lzy.part2;
/*
* 用数组实现堆
* 堆的定义?
* 二叉堆左右节点和父节点之间的关系?
* 如何使用数组进行是实现?
*
*
* */
public class Heap {
//定义一个数组用来存储数据
private int [] datas;
//定义一个变量来记录当前数据的数量
private int count;
/*
* 二叉堆的构造函数
*
* int size : 堆的大小
* */
public Heap(int size) {
if(size <= 0) {
throw new RuntimeException("size can not be null !");
}
datas = new int [size];
}
//获取当前堆的大小
public int size() {
if(datas == null) {
throw new RuntimeException("Heap is null !");
}else {
return count;
}
}
//判断是否为空
public boolean isEmpty() {
if(datas == null || datas.length == 0) {
return true;
}else {
return false;
}
}
}