热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java实现优先队列:二叉堆详解

本文详细介绍了二叉堆的概念及其在Java中的实现方法。二叉堆是一种特殊的完全二叉树,具有堆性质,常用于实现优先队列。
### 一、概念介绍 #### 1. 完全二叉树 完全二叉树是指除了最后一层外,所有其他层都是满的,并且最后一层的节点从左到右依次排列。 #### 2. 堆性质 - **最小堆**:父节点的值小于或等于其子节点的值。 - **最大堆**:父节点的值大于或等于其子节点的值。 ![完全二叉树示例](https://img-blog.csdn.net/20170618115514882?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVuZ3FpYW93b2xm/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 由于二叉堆是完全二叉树,因此父节点和子节点的位置存在一定的关系。假设我们将二叉堆的第一个元素放在数组索引为1的位置,则父节点和子节点的位置关系如下: - 索引为i的左孩子的索引是 (2*i) - 索引为i的右孩子的索引是 (2*i+1) - 索引为i的父节点的索引是 (i/2) 因此,我们通常使用数组来实现二叉堆。 ### 二、实现思路 #### 1. 插入(上滤) - 在堆的末尾创建一个空穴。 - 如果新元素可以直接放入该空穴而不违反堆的性质,则插入完成。 - 否则,将空穴的父节点的值移入该空穴,空穴向上移动一步。 - 重复上述过程,直到新元素可以放入空穴中。 ![插入示例](https://img-blog.csdn.net/20170618122233991?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVuZ3FpYW93b2xm/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) #### 2. 删除根元素(最小值/最大值)(下滤) - 将根节点删除,形成一个空穴。 - 将堆的最后一个元素移到空穴中。 - 如果该元素可以直接放入空穴而不违反堆的性质,则删除完成。 - 否则,将空穴的两个子节点中较小的一个移入空穴,空穴向下移动一步。 - 重复上述过程,直到该元素可以放入空穴中。 ![删除示例](https://img-blog.csdn.net/20170618122932738?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVuZ3FpYW93b2xm/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) #### 3. 创建堆 - **简单方法**:使用N个相继的插入操作来构建堆,每个插入操作的时间复杂度为O(logN),总时间复杂度为O(N logN)。 - **高效方法**:先保持堆的结构性,然后通过下滤操作确保堆的性质。这种方法的时间复杂度为O(N)。 ### 三、代码实现 ```java import java.util.ArrayList; /** * 头元素存储于1位置 * i节点的左孩子位置2*i,右孩子位置2*i+1,父亲位置i/2 */ public class BinaryHeap> { private ArrayList array; // 存储信息 private int currentSize; // 当前大小 public BinaryHeap() { array = new ArrayList<>(); array.add(null); } /** * 将数组转化为二叉堆 * @param array */ public BinaryHeap(ArrayList array) { currentSize = array.size(); for (int i = 1; i <= currentSize; i++) { this.array.set(i, array.get(i - 1)); // 保证结构性 } for (int i = currentSize / 2; i > 0; i--) { percolateDown(i); // 保证堆性 } } /** * 插入 * @param x */ public void insert(T x) { int hole = currentSize + 1; // 空穴的初始位置 array.add(x); for (; hole > 1 && x.compareTo(array.get(hole / 2)) <0; hole /= 2) { array.set(hole, array.get(hole / 2)); // 上滤 } array.set(hole, x); // 找到合适的位置 currentSize++; } /** * 查找最小元素 * @return */ public T findMin() { return array.get(1); } /** * 删除最小元素 * @return */ public T deleteMin() { if (currentSize <1) { System.out.println("BinaryHeap is Empty"); } T minElement = array.get(1); // 获取最小元素 array.set(1, array.get(currentSize)); // 将末尾元素存入 array.remove(currentSize--); // 移除最后元素,并使大小-1 if (currentSize > 0) { percolateDown(1); // 下滤 } return minElement; } /** * 删除任一元素 * @return 元素不存在,返回-1;删除成功,返回该元素的下标 */ public int delete(T x) throws Exception { if (currentSize <1) { throw new Exception("BinaryHeap is Empty"); } int index = array.indexOf(x); // 获取x的索引 if (index == -1) { return -1; } array.set(index, array.get(currentSize)); array.remove(currentSize--); percolateDown(index); // 下滤 return index; } /** * 下滤 */ public void percolateDown(int hole) { int child; T temp = array.get(hole); // 需要下滤的元素,临时存储 for (; hole * 2 <= currentSize; hole = child) { child = hole * 2; if (child 0) { child++; // child不为最后一个元素,且右元素小于左元素时:child为右元素,否则child为左元素 } if (temp.compareTo(array.get(child)) > 0) { array.set(hole, array.get(child)); // temp大于较小的元素,将空穴下滤一层 } else { break; // 找到合适的位置,跳出循环替换 } } array.set(hole, temp); } public static void main(String[] args) { int numItems = 1000; BinaryHeap h = new BinaryHeap<>(); int i = 37; for (i = 37; i != 0; i = (i + 37) % numItems) { h.insert(i); } for (i = 1; i
推荐阅读
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 2017-2018年度《网络编程与安全》第五次实验报告
    本报告详细记录了2017-2018学年《网络编程与安全》课程第五次实验的具体内容、实验过程、遇到的问题及解决方案。 ... [详细]
  • 本文探讨了如何通过一系列技术手段提升Spring Boot项目的并发处理能力,解决生产环境中因慢请求导致的系统性能下降问题。 ... [详细]
  • 本文探讨了在 SQL Server 中使用 JDBC 插入数据时遇到的问题。通过详细分析代码和数据库配置,提供了解决方案并解释了潜在的原因。 ... [详细]
  • 深入解析Java多线程与并发库的应用:空中网实习生面试题详解
    本文详细探讨了Java多线程与并发库的高级应用,结合空中网在挑选实习生时的面试题目,深入分析了相关技术要点和实现细节。文章通过具体的代码示例展示了如何使用Semaphore和SynchronousQueue来管理线程同步和任务调度。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 本文深入探讨了MySQL中常见的面试问题,包括事务隔离级别、存储引擎选择、索引结构及优化等关键知识点。通过详细解析,帮助读者在面对BAT等大厂面试时更加从容。 ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • 软件工程课堂测试2
    要做一个简单的保存网页界面,首先用jsp写出保存界面,本次界面比较简单,首先是三个提示语,后面是三个输入框,然 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 本文详细解析了Java中throw和throws的关键区别,同时涵盖了JDK的定义、Java虚拟机的关键约定、Java的跨平台性、自动垃圾回收机制、源文件结构、包的概念及作用等多个核心知识点,旨在帮助学生更好地准备Java期末考试。 ... [详细]
  • KMP算法是一种高效的字符串模式匹配算法,能够在不进行回溯的情况下完成匹配,其时间复杂度为O(m+n),其中m和n分别为文本串和模式串的长度。本文将详细介绍KMP算法的工作原理,并提供C语言实现。 ... [详细]
author-avatar
mobiledu2502873617
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有