优先队列与堆

1.什么是优先队列

    队列是一种特殊的线性表,其插入和删除的过程分别在线性表的两端进行。向队列中插入元素的过程称为入队,删除元素的过程为出队,入队的一端称为对尾,出队的一段称为队头。因为插入和删除分别是在队尾和队头进行的,所以队列的特点是先进先出(FIFO)。队列的主要操作有:

优先队列继承了队列的接口,但是一种特殊的队列。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。不管队列里的元素是怎样的,在出队是时候,出队的永远都是比较级最大的元素。这个时候如果还采用原来数组和链表结构的话,每次出队都要通过遍历所有元素来取出比较级最高的元素,这样时间复杂度为O(n),效率太低了,所以我们采用一种新的结构——堆来处理。

2.什么是堆

堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆和普通树的区别

堆看上去和树一样,它们之间有相似之处也有一些不同。我们来看一下两者的主要差别:

 

节点的顺序。在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用。普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额为是我内存。堆仅仅使用一个数据来村塾数组,且不使用指针。当前节点的左子节点 =当前节点的索引 * 2 ,当前节点的右子节点 = 当前节点的索引 + 1,相当于树的层次遍历

平衡。二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

搜索。在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。

代码实现

下面通过构建一个堆来实现优先队列

import java.util.ArrayList;    //借用java自带的动态数组来避免写扩展代码
import java.util.Collection;   

public class MaxHeap<E extends Comparable<E>> {    //继承比较接口,可以比较自定义的数据类型

    private ArrayList<E> data;

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

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

    public MaxHeap(Collection<E>arr){      //把集合通过构造方法转换成最大堆
        data = new ArrayList<E>(arr);
        for(int i = parent(arr.size() - 1) ; i >= 0 ; i --)    
            siftDown(i);
    }

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

    // 返回一个布尔值, 表示堆中是否为空
    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;
    }

    // 向堆
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值