Java优先队列(堆)理解和使用

简介: Java优先队列(堆)理解和使用

1 什么是优先队列(堆)

1.1 继承关系

首先看下Java中堆的继承关系,可以看出堆实现了队列的全部方法。

1.2 堆的数据结构

1.3 特征:

(1)二叉堆是一个完全二叉树

(2)根节点总是大于左右子节点(大顶堆),或者是小于左右子节点(小顶堆)。

1.4 常见方法

add()

//调用了offer方法
  public boolean add(E e) {
      return offer(e);
  }
    //判断输入元素是否为空,如果不为空
  public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            //增加容量
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            //上浮方法--(小根堆)将小的元素进行上浮
            siftUp(i, e);
        return true;
  }

offer()

//判断输入元素是否为空,如果不为空
  public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            //增加容量
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            //上浮方法--(小根堆)将小的元素进行上浮
            siftUp(i, e);
        return true;
  }
    //私有方法
    /*
    作用:在k位置插入项x,通过提升x到树的顶端,保持堆不变,直到它大于或等于它的父结点,
    或者是根结点
    */
  private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

peek()

//弹出堆顶的元素
    public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }

remove()

//先找出位置,再进行删除
  public boolean remove(Object o) {
        int i = indexOf(o);
        if (i == -1)
            return false;
        else {
            removeAt(i);
            return true;
        }
    }

contains()

//查看元素是否存在的本质就是看看有没有他的位置
  public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

toArray()

public Object[] toArray() {
        return Arrays.copyOf(queue, size);
    }
    //与上边的不同就是需要有一个泛型
    public <T> T[] toArray(T[] a) {
        final int size = this.size;
        if (a.length < size)
            //返回一个新的带泛型的数组
            return (T[]) Arrays.copyOf(queue, size, a.getClass());
        System.arraycopy(queue, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

size()

public int size() {
        return size;
    }

clear()

//遍历一次 全部置为null
  public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            queue[i] = null;
        size = 0;
    }

poll()

//返回并删除第一个元素
    public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        //取出堆顶元素
        E result = (E) queue[0];
        //取出最后一个元素
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            //做下沉操作
            siftDown(0, x);
        return result;
    }

2 Java中堆的使用(小根堆为例)

2.1 堆排序

/**
 * @author ymx
 */
public class TestPriorityQueue {
    /**
     * 声明一个堆
     */
    public PriorityQueue<Integer> queue = new PriorityQueue();
    /**
     * 初始化数据
     *
     * @param items
     */
    public void init(int[] items) {
        for (int i = 0; i < items.length; i++) {
            //将数据放入堆中
            queue.add(items[i]);
        }
    }
    /**
     * 排序操作
     *
     * @return
     */
    public int[] sort() {
        int[] items = new int[queue.size()];
        int i = 0;
        while (queue.size() > 0) {
            //弹出并删除堆顶元素
            items[i] = queue.poll();
            i++;
        }
        return items;
    }
    public static void main(String[] args) {
        TestPriorityQueue test = new TestPriorityQueue();
        test.init(new int[]{5, 6, 4, 3, 8, 9, 7, 1, 2});
        int[] sort = test.sort();
        System.out.print("排序结果:");
        for (Integer i : sort) {
            System.out.print(i + "  ");
        }
    }
}

运行结果:

2.2 进程调度

堆在操作系统的进程调度中也被广泛使用,比如依据优先级进行的进程调度等等,在这里就不做详解啦


相关文章
|
3月前
|
Java
【Java基础面试三十二】、new String(“abc“) 是去了哪里,仅仅是在堆里面吗?
这篇文章解释了Java中使用`new String("abc")`时,JVM会将字符串直接量"abc"存入常量池,并在堆内存中创建一个新的String对象,该对象会指向常量池中的字符串直接量。
|
3月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
131 4
|
21小时前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
3月前
|
存储 算法 Java
解释 Java 堆空间和垃圾收集
【8月更文挑战第22天】
34 0
|
2天前
|
存储 Java 调度
Java 中的优先队列 PriorityQueue 详解
【10月更文挑战第22天】优先队列 PriorityQueue 是一种非常实用的数据结构,在许多场景中都能发挥重要作用。通过深入了解其特点和用法,我们可以更好地利用它来解决实际问题。
|
19天前
|
存储 算法 Java
🏗️Java零基础:深入了解Java 堆
【10月更文挑战第2天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
19 3
|
2月前
|
JSON 前端开发 JavaScript
java中post请求调用下载文件接口浏览器未弹窗而是返回一堆json,为啥
客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗; > 正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。
112 2
|
21天前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
28 0
|
3月前
|
存储 Java 程序员
Java 中的堆栈和堆有什么区别?
【8月更文挑战第22天】
169 0
|
4月前
|
存储 Java 程序员
Java面试题:方法区在JVM中存储什么内容?它与堆内存有何不同?
Java面试题:方法区在JVM中存储什么内容?它与堆内存有何不同?
66 10