数据结构入门-8-堆和优先队列

一、优先队列的意义

普通队列: FIFO
优先队列:与入队顺序无关 ; 和优先级相关()

操作系统中任务调度的优先级
动态选择优先级最高的任务执行
在这里插入图片描述
关键词:动态 处理任务调度

直接复用队列

在这里插入图片描述

所以 用堆可以很方便的实现二叉树

二、堆

2.1 二叉堆Binary Heap

在这里插入图片描述
二叉堆是一棵完全二叉树
满二叉树:除了叶子结点,其他的左右结点都不为空
完全二叉树:不一定是满二叉树,但是缺失部分一定在左下侧,从左到右(19 、17 、 15)

二叉堆的性质

  1. 堆中的某个节点的值总是不大约其父节点的值
  2. 最大堆(最小堆)

2.2 用数组实现二叉堆

在这里插入图片描述
如上图,可以用数组来实现二叉堆,

  • 左节点 = i * 2
  • 右节点 = i * 2 + 1
  • 父节点 = i / 2
public class MaxHeap<E extends Comparable<E>> {

    private Array<E> data;

    public MaxHeap(int capacity){
        data = new Array<>(capacity);
    }

    public MaxHeap(){
        data = new Array<>();
    }

    // 返回堆中的元素个数
    public int size(){
        return data.getSize();
    }

    // 返回一个布尔值, 表示堆中是否为空
    public boolean isEmpty(){
        return data.isEmpty();
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
    private int parent(int index){
        if(index == 0)
            throw new IllegalArgumentException("index-0 doesn't have parent.");
        return (index - 1) / 2;
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
    private int leftChild(int index){
        return index * 2 + 1;
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
    private int rightChild(int index){
        return index * 2 + 2;
    }
}

2.2.1 像堆中添加元素

直接添加到叶子节点,但是这样就会产生大小不满足小于父亲节点
Sift Up 上浮
在这里插入图片描述

    // 向堆中添加元素
    public void add(E e){
        data.addLast(e);
        siftUp(data.getSize() - 1);
    }

    private void siftUp(int k){

        while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
            data.swap(k, parent(k));
            k = parent(k);
        }
    }

2.2.2 从堆中取出元素

堆的性质:只能取出 根节点的 元素(最大的元素)

在这里插入图片描述

维护堆的步骤:

  1. 最后一个元素 移动到 根节点
  2. 现在对比根节点 & 左右两个孩子结点,sift down 最大的

在这里插入图片描述

    // 取出堆中最大元素
    public E extractMax(){

        E ret = findMax();

        data.swap(0, data.getSize() - 1);
        data.removeLast();
        siftDown(0);

        return ret;
    }

    private void siftDown(int k){

        while(leftChild(k) < data.getSize()){
            int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置
            if( j + 1 < data.getSize() &&
                    data.get(j + 1).compareTo(data.get(j)) > 0 )
                j ++;
            // data[j] 是 leftChild 和 rightChild 中的最大值

            if(data.get(k).compareTo(data.get(j)) >= 0 )
                break;

            data.swap(k, j);
            k = j;
        }
    }

三、堆 实现 优先队列

public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {

    private MaxHeap<E> maxHeap;

    public PriorityQueue(){
        maxHeap = new MaxHeap<>();
    }

    @Override
    public int getSize(){
        return maxHeap.size();
    }

    @Override
    public boolean isEmpty(){
        return maxHeap.isEmpty();
    }

    @Override
    public E getFront(){
        return maxHeap.findMax();
    }

    @Override
    public void enqueue(E e){
        maxHeap.add(e);
    }

    @Override
    public E dequeue(){
        return maxHeap.extractMax();
    }
}

3.1 其他堆

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

oifengo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值