Java实现堆算法

news2024/12/29 19:05:29

堆是一种特殊的数据结构,它是一棵完全二叉树,且满足堆的性质:对于每个节点,它的值都不小于(或不大于)它的孩子节点的值。根节点的值就是堆中的最大值(或最小值)。

Java中提供了一个Heap类,可以用来实现堆的操作。Heap类是一个抽象类,它定义了堆的基本操作方法,如插入、删除、获取最大(或最小)值等。

要使用Heap类,需要创建一个具体的实现类,例如MaxHeap和MinHeap。这些类继承自Heap类,并实现了具体的插入、删除、获取最大(或最小)值等方法。下面我们以MaxHeap为例,来详细介绍如何实现堆。

MaxHeap的实现思路如下:

  1. 定义一个数组来保存堆的元素,数组下标从1开始。

  2. 定义一个变量来记录堆中元素的数量。

  3. 实现插入方法:新元素插入到数组最后,然后使用上滤操作将新元素沿着路径向上移动,直到堆的性质被满足。

  4. 实现删除方法:移除堆顶元素(数组下标为1的元素),然后将数组最后一个元素替换到堆顶,使用下滤操作将新元素沿着路径向下移动,直到堆的性质被满足。

  5. 实现获取最大值方法:直接返回堆顶元素。

  6. 实现堆排序方法:依次取出堆顶元素,将其放到一个新的数组中,然后重新调整堆。

以下是MaxHeap的代码实现:

public class MaxHeap<T extends Comparable<T>> {
    private T[] heap; // 堆元素数组
    private int size; // 堆元素数量

    @SuppressWarnings("unchecked")
    public MaxHeap(int capacity) {
        heap = (T[]) new Comparable[capacity + 1]; // 数组下标从1开始
        size = 0;
    }

    public void insert(T value) {
        if (size == heap.length - 1) {
            resize();
        }

        heap[++size] = value; // 新元素插入到数组最后
        swim(size); // 上滤操作
    }

    public T deleteMax() {
        if (size == 0) {
            throw new NoSuchElementException();
        }

        T max = heap[1]; // 堆顶元素
        heap[1] = heap[size--]; // 将数组最后一个元素替换到堆顶
        sink(1); // 下滤操作
        heap[size + 1] = null; // 释放旧的堆顶元素

        return max;
    }

    public T getMax() {
        if (size == 0) {
            throw new NoSuchElementException();
        }

        return heap[1];
    }

    public void heapSort(T[] arr) {
        heapify(arr); // 初始化堆
        for (int i = size; i > 0; i--) {
            arr[i - 1] = deleteMax(); // 依次取出堆顶元素
        }
    }

    private void swim(int k) {
        while (k > 1 && heap[k].compareTo(heap[k / 2]) > 0) { // 父节点小于当前节点,上滤
            swap(k, k / 2);
            k /= 2; // 移动到父节点
        }
    }

    private void sink(int k) {
        while (2 * k <= size) { // 如果有左孩子
            int j = 2 * k;
            if (j < size && heap[j].compareTo(heap[j + 1]) < 0) { // 选择左右孩子中较大的那个
                j++;
            }

            if (heap[k].compareTo(heap[j]) >= 0) { // 如果父节点不小于孩子节点,下滤结束
                break;
            }

            swap(k, j); // 父节点和子节点交换
            k = j; // 移动到子节点
        }
    }

    private void heapify(T[] arr) {
        heap = (T[]) new Comparable[arr.length + 1];
        size = arr.length;

        System.arraycopy(arr, 0, heap, 1, arr.length); // 复制数组元素到堆中

        for (int i = size / 2; i >= 1; i--) { // 倒序下滤,从最后一个非叶子节点开始
            sink(i); // 下滤操作
        }
    }

    private void resize() {
        int newSize = heap.length * 2;
        heap = Arrays.copyOf(heap, newSize);
    }

    private void swap(int i, int j) {
        T temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }
}

上面的代码实现了MaxHeap类,它支持插入、删除、获取最大值和堆排序等操作。堆排序的实现就是先将数组元素初始化成一个堆,然后依次取出堆顶元素,进行排序。

MaxHeap类中使用了泛型,可以存储任意类型的元素,只要实现了Comparable接口。使用时,可以像下面这样创建一个MaxHeap对象,然后调用其方法进行操作:

MaxHeap<Integer> maxHeap = new MaxHeap<>(10);
maxHeap.insert(3);
maxHeap.insert(1);
maxHeap.insert(4);
maxHeap.insert(1);
maxHeap.insert(5);
System.out.println(maxHeap.deleteMax()); // 输出:5
System.out.println(maxHeap.getMax()); // 输出:4

Integer[] arr = {3, 1, 4, 1, 5};
maxHeap.heapSort(arr);
System.out.println(Arrays.toString(arr)); // 输出:[1, 1, 3, 4, 5]

总的来说,实现堆的关键在于实现上滤和下滤操作。上滤操作用于插入新元素时,将其从叶子节点沿着路径向上移动,下滤操作用于删除堆顶元素时,将最后一个元素从根节点沿着路径向下移动,维护堆的性质。堆排序的实现就是先将数组初始化成一个堆,然后依次取出堆顶元素,进行排序。最后,需要注意的是,在Java中实现堆可以使用Heap类,但也可以自己实现一个堆类,可以根据具体需求进行设计和优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1234781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法分析与设计课后练习22

设W(5,7,10,12,15,18,20)和M35&#xff0c;使用过程SUMOFSUB找出W种使得和数等于M的全部子集并画出所生成的部分状态空间树

Linux C 网络编程概述

网络编程 计算机网络概述分类网络体系结构通信协议通信流程网络通信帧格式以太网帧格式分析ARP 协议分析IP 数据报分析IP分类IP 分配子网掩码 TCP 段分析 TCP三次握手协议 ⭐TCP四次挥手协议 ⭐ TCP编程基于 TCP 客户端编程-步骤说明基于 TCP 服务器端编程-步骤说明基于 TCP 服…

TypeError: expected np.ndarray (got Tensor)解决办法

文章目录 一、错误展示二、错误分析三、解决办法四、其余解决办法总结 一、错误展示 二、错误分析 这个错误表示正在尝试将一个PyTorch的Tensor对象作为numpy的ndarray对象来使用。我们需要使用numpy的ndarray而不是PyTorch的Tensor。 三、解决办法 在我的程序中去掉这一行代…

Redis跳跃表

前言 跳跃表(skiplist)是一种有序数据结构&#xff0c;它通过在每一个节点中维持多个指向其他节点的指针&#xff0c;从而达到快速访问节点的目的。 跳跃表支持平均O(logN)&#xff0c;最坏O(N)&#xff0c;复杂度的节点查找&#xff0c;还可以通过顺序性来批量处理节点…

局域网文件共享神器:Landrop

文章目录 前言解决方案Landrop软件界面手机打开效果 软件操作 前言 平常为了方便传文件&#xff0c;我们都是使用微信或者QQ等聊天软件&#xff0c;互传文件。这样传输有两个问题&#xff1a; 必须登录微信或者QQ聊天软件。手机传电脑还有网页版微信&#xff0c;电脑传手机比…

鸿蒙4.0开发笔记之DevEco Studio启动时不直接打开原项目(二)

1、想要在DevEco Studio启动时不直接打开关闭前的那个项目&#xff0c;可以在设置中进行。 有两个位置可以进入“设置”&#xff0c;一个是左上角的File>Settings&#xff0c;二是右上方的设置图标。 2、进入Settings界面以后&#xff0c;选择Appearance&Behavior下面…

【C++】泛型编程 ⑨ ( 类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中 | 类模板 的 外部友元函数问题 )

文章目录 一、类模板 - 函数声明与函数实现分离1、函数声明与函数实现分离2、代码示例 - 函数声明与函数实现分离3、函数声明与函数实现分离 友元函数引入 二、普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中三、类模板的运算符重载 - 函数声明 和 函数实现 写在同…

AMEYA360:蔡司扫描电镜Sigma系列:扫描电子显微镜的用途原来这么多

扫描电子显微镜是一种全自动的、非破坏性的显微分析系统&#xff0c;可针对无机材料和部分有机材料&#xff0c;迅速提供在统计学上可靠且可重复的矿物学、岩相学和冶金学数据&#xff0c;在采矿业&#xff0c;可用于矿产勘查、矿石表征和选矿工艺优化&#xff0c;在石油和天然…

Oracle数据库笔记(一)

1.概述 Oracle版本 19c 在线迁移、自适应扫描、自适应数据共享11g 企业管理器、自动化诊断工具、自动化性能管理 Oracle特点 可用性强可扩展性强数据安全性强稳定性强 常见数据库 小 Access中 SQL Server、MySQL大 Oracle、DB2 2.数据、数据库、数据库管理系统、数据库系…

【项目管理】甘特图(1)——认识甘特图

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 今天学习下甘特图的绘制&#xff0c;以下为学习笔记。 一、什么是甘特图 甘特图是可以直观展示项目进展随时间走势和联系的条状图。是一种常见的项目管理工具。 项目的时间用横轴表示&#xff0c;项目的进度用纵轴表…

vue diff算法原理以及v2v3的区别

diff算法简介 diff算法的目的是为了找到哪些节点发生了变化&#xff0c;哪些节点没有发生变化可以复用。如果用最传统的diff算法&#xff0c;如下图所示&#xff0c;每个节点都要遍历另一棵树上的所有节点做比较&#xff0c;这就是o(n^2)的复杂度&#xff0c;加上更新节点时的…

可视化大屏时代的到来:智慧城市管理的新思路

随着科技的不断发展&#xff0c;智能芯片作为一种新型的电子元件&#xff0c;被广泛应用于各个领域&#xff0c;其中智慧芯片可视化大屏是一种重要的应用形式。 一、智慧芯片可视化大屏的优势 智慧芯片可视化大屏是一种将智能芯片与大屏幕显示技术相结合的产品&#xff0c;山海…

算法分析与设计课后练习23

求下面的0-1背包问题 &#xff08;1&#xff09;N5,M12,(p1,p2,…,p5)(10,15,6,8,4),(w1,w2,…,w5)(4,6,3,4,2) &#xff08;2&#xff09;N5,M15,(p1,p2,…,p5)(w1,w2,…,w5)(4,4,5,8,9)

Springboot+vue的社区医院管理系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的社区医院管理系统(有报告)&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的应急物资管理系统&#xff0c;采用M&#xff08;model&#xff09;V&am…

【Django使用】4大模块50页md文档,第4篇:Django请求与响应和cookie与session

当你考虑开发现代化、高效且可扩展的网站和Web应用时&#xff0c;Django是一个强大的选择。Django是一个流行的开源Python Web框架&#xff0c;它提供了一个坚实的基础&#xff0c;帮助开发者快速构建功能丰富且高度定制的Web应用 Django全套笔记地址&#xff1a; 请移步这里 …

动态规划十大经典问题

动态规划十大经典问题 动态规划十大经典问题 数塔取数问题、矩阵取数问题、最大连续子段和、最长递增子序列、最长公共子序列、最长公共子串、最短编辑距离、背包问题、正整数分组、股票买卖问题。 1、数塔取数问题 // 数塔取数问题 public static int dataTowerAccess(int[]…

一文读懂 Linux 网络 IO 模型

文章目录 1.从一个问题说起2.多进程模型3.多线程模型4.I/O 多路复用5.select、poll、epoll 的区别&#xff1f;5.1 select5.2 poll5.3 epoll5.4 两种事件触发模式 参考文献 1.从一个问题说起 互联网发展历史上&#xff0c;曾经有一个著名的问题&#xff1a;C10K 问题。 C 是 …

5-4计算一串字符的空格数字字符其他

#include<stdio.h> int main(){char c;int space0;//空格int letters0;//英文字母int numbers0;//数字int others0;//其他字符printf("请输入一行字符&#xff1a;");while((cgetchar())!\n)//获取字符的内容&#xff0c;到\n停止{if(c>a&&c<z|…

AR眼镜方案—单目光波导AR智能眼镜

光波导技术是一项具有前沿意义的技术&#xff0c;它能够将光线反射180度&#xff0c;使得眼镜框架内置的MicroLED屏幕的图像通过多次反射与扩散后准确地传递到人眼中。采用MicroLED显示技术的AR智能眼镜不仅体积显著缩小&#xff0c;屏幕只有0.68英寸大小&#xff0c;并且还能够…

【PostgreSQL】解决PostgreSQL时区(TimeZone)问题

问题描述 最近在使用PostgreSQL中&#xff0c;对行记录进行设置创建时间&#xff08;created_time&#xff09;时&#xff0c;出现了设置了now()时间而数据库中写入的数据是不一致的数据。 eg&#xff1a; insert into dept ( created_at, updated_at) VALUES (now(),now())…