优先队列
1.定义
一类可以对队列中任意优先元素进行操作的队列。
2.图解
3.分类
①最大优先队列
②最小优先队列
③(最小)索引优先队列
4.最大优先队列详解
由最大堆构成,便于找到优先级最高的元素。
(1).最大堆
①头结点处元素是整个堆中最大的元素;
②每个结点都大于它的子结点。
(2).API设计
(3).代码实现
<1>.属性
//储存T类型元素的数组
private T[] items;
//元素个数
private int N;
<2>.构造方法
//构造方法(初始化数组的长度)
public MaxPriorityQueue_最大优先队列(int Capacity){
//初始化数组
items = (T[]) new Comparable[Capacity+1];
//初始化长度
N = 0;
}
<3>功能方法
a.判断索引i处元素是否小于索引j处元素
//判断堆中索引i处元素是否小于j处
private boolean less(int i,int j){
return items[i].compareTo(items[j])<0;
}
b.交换索引i处元素与索引j处元素位置
//交换索引i处元素与索引j处元素
private void exchange(int i,int j){
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
c.获取队列的长度
//获取队列中元素的个数
public int size(){
return N;
}
d.判断队列是否为空
//记录队列是否为空
public boolean isEmpty(){
return N == 0;
}
e.向队列中插入元素t
//向队列中插入元素t
public void insert (T t){
//队列长度+1,让队列数组末尾元素为t
items[++N] = t;
//利用上浮算法使新元素到正确的位置
swim(N);
}
f.上浮算法
//上浮算法
private void swim(int k){
//利用循环使新元素向上遍历,如果新元素大于父结点元素,则进行上浮操作,否则,结束循环
while(k>1){
if (less(k,k/2)){
break;
}
exchange(k,k/2);
//变换k值
k = k/2;
}
}
g.删除队列中元素的最大值,并返回该值
//删除队列中的最大元素
public T deleteMax(){
//创建一个变量储存删除的最大元素,便于返回
T max = items[1];
//交换根结点元素与数组尾部结点的元素(根结点元素最大)
exchange(1,N);
//删除尾部结点的元素
items[N] = null;
//队列长度-1
N--;
//对新的根结点元素进行下沉算法操作
sink(1);
//返回最大元素
return max;
}
h.下沉算法
//下沉算法
private void sink(int k){
//利用循环新元素向下遍历,分类讨论子结点的情况,如果元素小于子结点 的较大元素,则下沉操作
while(k*2<=N){
//创建一个变量记录子结点较大值索引
int bigIndex;
//存在两个子结点的情况
if (k*2+1<=N){
//左子结点小于右子结点元素的情况
if (less(k*2,k*2+1)){
bigIndex = k*2+1;
}else{
bigIndex = k*2;
}
}
//仅存在左子结点的情况
else{
bigIndex = k*2;
}
//如果k元素大于其子结点的元素,结束循环
if (less(bigIndex,k)){
break;
}
//交换元素
exchange(bigIndex,k);
//更新k的值
k = bigIndex;
}
}
5.最小优先队列详解
由最小堆构成,便于找到优先级最低的元素。
(1).最小堆
①最小元素放在数组的索引1处;
②每个结点数据总小于它的两子结点元素。
(2).API设计
(3).代码实现
<1>.属性
//存储队列中结点元素的数组
private T[] items;
//队列元素个数
private int N;
<2>.构造方法
//构造方法(初始化队列)
public MinPriorityQueue_最小优先队列(int Capacity) {
//初始化数组长度
items = (T[]) new Comparable[Capacity + 1];
//初始化元素个数
N = 0;
}
<3>.功能方法
a.判断索引i处元素是否小于索引j处元素
//判断索引i处元素是否小于索引j处
private boolean less(int i, int j) {
return items[i].compareTo(items[j]) < 0;
}
b.交换索引i处元素和索引j处元素
//交换索引i处元素与索引j处元素
private void exchange(int i, int j) {
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
c.获得队列的长度
//获得队列中元素个数
public int size() {
return N;
}
d.判断队列是否为空
//判断队列是否为空
public boolean isEmpty() {
return N == 0;
}
e.向队列中插入元素t
//插入元素t
public void insert(T t) {
//数组长度+1,且将数组末尾元素变为t
items[++N] = t;
//上浮算法使新元素到正确的位置
swim(N);
}
f.上浮算法
//上浮算法
private void swim(int k) {
//循环向上遍历,如果新元素大于父结点元素,则结束循环,反之,交换两元素。
while (k > 1) {
//如果父结点元素小于新元素,则结束循环
if (less(k / 2, k)) {
break;
}
exchange(k / 2, k);
//更新k的值
k = k / 2;
}
}
g.删除队列中最小元素,并返回该值
//删除队列中的最小元素
public T deleteMin() {
//设置变量储存数组的首位(首位为最小元素),便于返回
T min = items[1];
//交换数组的首位和末尾
exchange(1, N);
//删除数组的末尾,即最小元素
items[N] = null;
//队列长度-1
N--;
//对根结点下沉算法,到正确的位置即可
sink(1);
//返回删除的最小元素
return min;
}
h.下沉算法
//下沉算法
private void sink(int k) {
//循环向下遍历,考虑子结点的存在情况,如果当前结点元素小于子结点,结束循环,否则,交换两者元素。
while (k * 2 <= N) {
//设置变量储存子结点较小值索引
int smallIndex;
//子结点的左右结点都存在的情况
if (k * 2 + 1 <= N) {
//当左子结点小于右子结点时
if (less(k * 2, k * 2 + 1)) {
smallIndex = k * 2;
} else {
smallIndex = k * 2 + 1;
}
}
//子结点仅存在左子结点的情况
else {
smallIndex = k * 2;
}
//如果元素k小于他的子结点的较小值,则结束循环,否则,交换两者元素
if (less(k, smallIndex)) {
break;
}
exchange(k, smallIndex);
//更新k的值
k = smallIndex;
}
}
6.最小索引优先队列
(1).定义
能够通过索引访问已存在优先队列中的元素的一种数据结构。
(2).实例
存放元素数组items(绑定索引k与元素t):
逻辑数组pq用来储存items的索引值(经过堆排序,有序的数组)
pq的逆序数组qp
(3).API设计
(4).代码实现
<1>.属性
//存放元素的数组
private T[] items;
//存放元素索引的数组(需堆有序)
private int[] pq;
//存放元素索引数组的逆序数组
private int[] qp;
//优先队列中的长度
private int N;
<2>.构造方法
//构造方法
public IndexMinPriorityQueue_最小索引优先队列(int Capacity){
//初始化存放元素数组
items = (T[])new Comparable[Capacity];
//初始化存放元素索引的数组
pq = new int[Capacity+1];
//初始化存放元素索引数组的逆序数组
qp = new int[Capacity+1];
//初始化数组的长度
N = 0;
//默认情况下,优先队列中无元素,令qp数组中所有元素均为-1;
for (int i = 0;i < qp.length;i++){
qp[i] = -1;
}
}
<3>.功能方法
a.判断索引i处元素是否小于索引j处
//判断队列中索引i处元素是否小于索引j处元素
private boolean less(int i,int j){
return items[pq[i]].compareTo(items[pq[j]])<0;
}
b.交换队列中索引i处元素与索引j处元素
//交换队列中索引i处元素与索引j处元素
private void exchange(int i,int j){
//由于原索引与元素值一一绑定,固应交换pq中的元素值
int temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
//更新qp数组中的对应关系
qp[pq[i]] = i;
qp[pq[j]] = j;
}
c.获取队列的长度&判断队列是否为空
//获取队列的长度
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N == 0;
}
d.判断队列中某索引处是否有元素&得到最小元素的索引
//判断队列中某索引处是否有元素
public boolean contains(int k){
return qp[k] != -1;
}
//得到最小元素的索引
public int minIndex(){
return pq[1];
}
e.向位置k处插入元素t(包含上浮算法)
//向位置k处插入元素t
public void insert(int k,T t){
//判断i处是否有元素,如果有元素,则插入失败
if (contains(k)){
//抛出异常提示语句
throw new RuntimeException("该索引已存在!");
}
//队列的长度+1
N++;
//存元素的数组索引k处改变元素
items[k] = t;
//pq数组中在数组末尾插入新索引k
pq[N] = k;
//更新qp数组元素
qp[k] = N;
//使存索引的数组pq上浮算法,到正确的位置(堆排序)
swim(N);
}
//上浮算法
private void swim(int k){
while(k > 1){
if (less(k/2,k)){
break;
}
exchange(k/2,k);
//更新k的值
k = k/2;
}
}
f.删除队列中最大元素,并返回该值(包含下沉算法)
//删除队列中最小的元素,并返回其值
public T deleteMin(){
//设置变量储存最小值,便于返回
T minValue = items[pq[1]];
//删除pq数组的第一位索引所对应的元素
items[pq[1]] = null;
//将pq中的最小值(即第一个值)变为最后的值
exchange(1,N);
//将qp中删除索引处元素变为-1
qp[pq[N]] = -1;
//将pq中的末尾元素索引值变为-1
pq[N] = -1;
//队列长度-1
N--;
//对pq中新的头元素进行下沉操作
sink(1);
//返回被删除的最小元素
return minValue;
}
//下沉算法
private void sink(int k){
int minIndex;
while(2*k <= N){
minIndex = k*2;
if (k*2+1 <= N){
if (less(2*k+1,2*k)){
minIndex = k*2+1;
}
}
if (less(minIndex,k)){
exchange(minIndex,k);
}
k = minIndex;
}
}
g.删除指定索引k处的元素
//删除指定索引k处的元素
public void delete(int k){
//找出k索引在pq中的索引
int i = qp[k];
exchange(i,N);
//删除对应索引处的元素索引
qp[pq[N]] = -1;
pq[N] = -1;
items[k] = null;
//队列长度-1
N--;
//由于不清楚k在队列中的具体位置,同时需要上浮与下沉
swim(i);
sink(i);
}
h.修改items中的索引i处的元素为t
//修改items中的索引i处的元素为t
public void changeItem(int i,T t){
//修改元素
items[i] = t;
//获得改动元素在pq中的索引
int k = qp[i];
//对pq中元素进行上浮或下沉
swim(k);
sink(k);
}
完!