堆排序-优先级队列

我们用堆排来实现优先级队列,那么优先级队列是什么,就是 我们给每一个任务都添加一个优先级,优先级越高执行的越早我们用,但是我们怎么能按照顺序优先拿到优先级高的任务呢,我们可以用排序 来进行,也可以用堆 排序来进行,效率更高

 如上图 索引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);
        }

    }}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三氧化真

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值