我们用堆排来实现优先级队列,那么优先级队列是什么,就是 我们给每一个任务都添加一个优先级,优先级越高执行的越早我们用,但是我们怎么能按照顺序优先拿到优先级高的任务呢,我们可以用排序 来进行,也可以用堆 排序来进行,效率更高
如上图 索引0 为 根节点 也就是parent,那么我们如何找到 他的 叶子节点呢? 如果用比大小直接排序的话,就不是堆排序,堆排序本质 就是用有序数组的形式,来形成树型结构,当我们知道 parent结点之后,他的child节点就遵循如下规律
parent=(child-1)/2
上浮
当我们添加元素的时候
我们可以先往数组的尾部添加,如上图的话 也就是 下一个元素要添加到的位置 就是数组的索引7 的位置,我们根据 索引7 为child 节点,然后根据上面的公式 找到 他的 parent节点为 索引3.,然后跟索引3的任务比较优先级,如果优先级比索引三处的任务大,我们把当前child节点的任务更新成parent节点的任务,然后我们在把child 节点更新成索引三,并且把再往上找一个parent节点,继续比较优先级。(翻译过来是 如果 索引7 的优先级比索引三的 优先级高,把索引三的任务 赋给索引7,然后 修改新的child节点为索引3,再继续找 parent节点,直到parent节点索引为0,或者parent节点的优先级比child节点优先级大为止 ) 这一操作 我们称之为 上浮操作
下潜
我们删除元素的时候
我们一个一个找,然后删除,最后还有重新排列堆,那样就太繁琐 太麻烦了,我们添加的时候 添加的是优先级最高的,所以删除的时候也可以先删除优先级最高的任务,所以我们可以这样 我们先把 优先级最高的 任务 跟 优先级最低的任务互换,然后从数组的尾部直接删除这个优先级最高的任务,然后以 索引0 为parent节点,找到 他的左右孩子节点,依次跟 左右孩子比较,如果 这个换过来的任务,也就是优先级比较低的任务 比左右孩子中的一个小,就把parent节点更新成左右孩子的其中一个,然后交换二者的任务,然后再根据 新的 parent 找到新的child 进行比较交换 ,知道父亲的优先级 大于 左右孩子或者 左右孩子的索引要数组越界了再停止比较
(翻译过来就是 索引0 节点 跟索引1 2 节点比较优先级 ,如果 索引1节点优先级 比 索引0 大,九把二者的 任务互换,然后以索引1为新的parent节点,索引3 4 为新的左右孩子节点,继续比较优先级) 这一操作称之为 下潜
代码实现
任务实体类
public class TaskEntry <T>{
T Task;
Integer Priority;
public TaskEntry(T task, Integer priority) {
Task = task;
Priority = priority;
}
@Override
public String toString() {
return "TaskEntry{" +
"Task=" + Task +
", Priority=" + Priority +
'}';
}
}
代码实现
public class BigHeap {
private TaskEntry[] arr;
/**
* 记录 堆的元素个数
*/
private int size;
//初始化 堆的大小
private int capacity;
public BigHeap(int capacity) {
this.capacity = capacity;
arr = new TaskEntry[capacity];
}
public Boolean isFull() {
return size == capacity;
}
/**
* @return {@code Boolean }
*/
public Boolean isEmpty() {
return size == 0;
}
/**
* 孩子= 应该添加到的数组的索引位置 也就是size
* 父亲=(孩子-1)/2
*
* @param entry
*/
public void add(TaskEntry entry) {
if (isFull()) {
return;
}
int child = size;
int parent = (child - 1) / 2;
while (child != 0 && entry.Priority > arr[parent].Priority) {
arr[child] = arr[parent];
child = parent;
parent = (child - 1) / 2;
}
arr[child] = entry;
size++;
}
public void delete() {
swap(0, --size);
arr[size] = null;
down(0);
}
private void down(int parent) {
int max = parent;
int left = parent * 2 + 1;
int right = left + 1;
while (true){
if (left < size && arr[left].Priority > arr[parent].Priority) {
max = left;
}
if (right < size && arr[right].Priority > arr[parent].Priority) {
max = right;
}
if (max == parent) {
break;
}
swap(parent,max);
parent=max;
left = parent * 2 + 1;
right = left + 1;
}
}
private void swap(int i, int j) {
TaskEntry taskEntry = arr[i];
arr[i] = arr[j];
arr[j] = taskEntry;
}
public void loop(){
for (TaskEntry taskEntry : arr) {
System.out.println(taskEntry);
}
}}