7. 堆的简单学习

news/2024/4/24 8:22:22/文章来源:https://blog.csdn.net/weixin_43830137/article/details/130323880

7. 堆

7.1 堆的定义

堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组实现

堆的特性:

  1. 它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。

  1. 它通常用数组来实现。

    ​ 具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子结点则分别在位置4,5,6和7,以此类推。

​ 如果一个结点的位置为k,则它的父结点的位置为[k/2],而它的两个子结点的位置则分别为2k和2k+1。这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或2k+1。

  1. 每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟我们之前学习的二叉查找树是有区别的。

7.2 堆的API设计

7.3 堆的实现_大顶堆

7.3.1 insert插入方法的实现

​ 堆是用数组完成数据元素的存储的,由于数组的底层是一串连续的内存地址,所以我们要往堆中插入数据,我们只能往数组中从索引1处开始,依次往后存放数据,但是堆中对元素的顺序是有要求的,每一个结点的数据要大于等于它的两个子结点的数据,所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候我们就需要通过一些方法让刚才插入的这个数据放入到合适的位置。

​ 所以,如果往堆中新插入元素,我们只需要不断的比较新结点a[k]和它的父结点a[k/2]的大小,然后根据结果完成数据元素的交换,就可以完成堆的有序调整。

7.3.2 delMax删除最大元素方法的实现

​ 由堆的特性我们可以知道,索引1处的元素,也就是根结点就是最大的元素,当我们把根结点的元素删除后,需要有一个新的根结点出现,这时我们可以暂时把堆中最后一个元素放到索引1处,充当根结点,但是它有可能不满足堆的有序性需求,这个时候我们就需要通过一些方法,让这个新的根结点放入到合适的位置。

7.3.3 堆的实现代码

package com.ynu.Java版算法.U7_堆.T1_堆的实现_大顶堆;public class Heap<T extends Comparable<T>>  {// 存储堆中的元素   数组存储元素private T[] items;// 堆的大小private int N;public Heap(int maxSize) {items = (T[]) new Comparable[maxSize+1];N = 0;}// 判断堆中索引i处的元素是否小于索引j处的元素private boolean less(int i, int j){return items[i].compareTo(items[j]) < 0;}//交换堆中i索引和j索引处的值private void exch(int i,int j){T temp = items[i];items[i] = items[j];items[j] = temp;}//往堆中插入一个元素public void insert(T t){items[++N] = t;swim(N);   // 上浮新插入的元素}//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置private void swim(int k){//如果已经到了根结点,就不需要循环了while (k > 1){//比较当前结点和其父结点if (less(k/2,k)){//父结点小于当前结点,需要交换exch(k/2,k);}k = k/2;}}//删除堆中最大的元素,并返回这个最大元素public T deleteMax(){T max = items[1];// 交换索引1和索引N处的元素exch(1,N);// 删除最后的元素items[N--] = null;// 下层sink(1);return max;}private void sink(int i) {//如果当前已经是最底层了,就不需要循环了while (2*i <= N){// 找到子节点中的较大者int max;if (2*i+1<=N){   // 存在右子节点max = less(2*i,2*i+1)?2*i+1:2*i;}else {         // 不存在右子节点max = 2*i;}//比较当前结点和子结点中的较大者,如果当前结点不小,则结束循环if (!less(i,max)){break;}exch(i,max);i = max;}}}

7.4 堆的实现_小顶堆

其实差不了太多。懒得写了。

7.5 堆排序

  1. 树的入门

实现步骤:

  1. 构造堆;

  2. 得到堆顶元素,这个值就是最大值;

  3. 交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;

  4. 对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;

  5. 重复2~4这个步骤,直到堆中剩一个元素为止。

API设计:

7.5.1 堆构造过程

方法一:

堆的构造,最直观的想法就是另外再创建一个和新数组数组,然后从左往右遍历原数组,每得到一个元素后,添加到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。

方法二:

上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组0length-1的数据拷贝到新数组的1length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。

堆构造完毕,堆有序。

7.5.2 堆排序过程

对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。

  1. 将堆顶元素和堆中最后一个元素交换位置;

  2. 通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的最右边)

  3. 重复1~2步骤,直到堆中剩最后一个元素。

结果,已排序

7.5.3 代码实现

package com.ynu.Java版算法.U7_堆.T3_堆排序;//堆排序代码
public class HeapSort {//对source数组中的数据从小到大排序public static void sort(Comparable[] source){//1.创建一个比原数组大1的数组Comparable[] heap = new Comparable[source.length + 1];//2.构建堆  -- 大顶堆了createHeap(source,heap);//3.堆排序//3.1定义一个变量,记录heap中未排序的所有元素中最大的索引int N = heap.length - 1;while (N!=1){//3.2交换heap中索引1处的元素和N处的元素  当前索引为1的元素已经是最大的元素了exch(heap,1,N);N--;sink(heap,1,N);}//4.heap中的数据已经有序,拷贝到source中System.arraycopy(heap,1,source,0,source.length);}//根据原数组source,构造出堆heap// String也是实现过Comparable接口的类,所以可以传进来。  是多态的应用。private static void createHeap(Comparable[] source,Comparable[] heap){//1.把source中的数据拷贝到heap中,从heap的1索引处开始填充System.arraycopy(source,0,heap,1,source.length);//2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作for (int i = (heap.length - 1) / 2; i > 0 ; i--) {sink(heap,i,heap.length-1);}}//判断heap堆中索引i处的元素是否小于索引j处的元素private static boolean less(Comparable[] heap,int i,int j ){return heap[i].compareTo(heap[j]) < 0;}//交换heap堆中i索引和j索引处的值private static void exch(Comparable[] heap,int i,int j){Comparable temp = heap[i];heap[i] = heap[j];heap[j] = temp;}//在heap堆中,对target处的元素做下沉,范围是0~rangeprivate static void sink(Comparable[] heap,int target,int range){// 没有子节点了就退出循环while (2*target <= range){//1.找出target结点的两个子结点中的较大值int max = 2*target;if (2*target +1 <= range){  // 存在右子节点if (less(heap,2*target,2*target + 1)){max = 2*target + 1;}}//2.如果当前结点的值小于子结点中的较大值,则交换if (less(heap,target,max)){exch(heap,target,max);}//3.更新target的值target = max;}}}package com.ynu.Java版算法.U7_堆.T3_堆排序;import java.util.Arrays;public class Main {public static void main(String[] args) {String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};HeapSort.sort(arr);System.out.println(Arrays.toString(arr));}
}

7.6 Java中的PriorityQueue实现堆

​ Java中PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示。PriorityQueue位于Java util包中,实际上这个队列就是具有“优先级”。既然具有优先级的特性,那么就得有个前后排序的“规则”。所以其接受的类需要实现Comparable 接口。该队列线程安全,不允许null值,入队和出队的时间复杂度是O(log(n))。

​ PriorityQueue 默认是小根堆,大根堆需要重写比较器。对与大根堆,就要借助于comparator比较器,来实现大根堆。

实现方法有两种

第一种: 匿名内部类

PriorityQueue<Integer>bigHeap=new PriorityQueue<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}
});

第二种: lambda表达式

PriorityQueue<Integer> bigHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);

堆排序:

package com.ynu.Java版算法.U7_堆.T4_API实现堆排序;import org.junit.Test;import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;public class Main {// 1. 大顶堆 实现升序@Testpublic void test() {String[] arr = {"B", "D", "C", "F", "E", "G", "H", "J", "I", "K", "A"};// 构建空大顶堆PriorityQueue<String> heap = new PriorityQueue<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o2.compareTo(o1);}});// 把元素放进大顶堆for (String s : arr) {heap.offer(s);}// 堆排序 —— 升序int k = arr.length - 1;int size = heap.size();for (int i = 0; i < size; i++) {arr[k--] = heap.poll();}System.out.println(Arrays.toString(arr));}// 1. 小顶堆 实现升序@Testpublic void test1() {String[] arr = {"B", "D", "C", "F", "E", "G", "H", "J", "I", "K", "A"};// 1.构建空的小顶堆PriorityQueue<String> heap = new PriorityQueue<>((o1,o2)->o1.compareTo(o2));// 2.元素放进小顶堆for (String s : arr) {heap.offer(s);}// 3.堆排序    升序排列int k = 0;int size = arr.length;for (int i = 0; i < size; i++) {arr[k++] = heap.poll();}System.out.println(Arrays.toString(arr));}}

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用python实现自动点击功能

猜你感兴趣 使用Pyqt5玩转ChatGpt内网文件共享服务快速搭建私有pip镜像源python设计模式-创建型模式docker搭建私有git服务器&#xff0c;项目备份和迁移redis持久化方案 被测点击界面 新建counter.html添加下面代码并保存,使用编辑器或浏览器打开 <!DOCTYPE html> &l…

23.4.21总结

正则表达式 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串&#xff0c;通常被用来检索、替换那些符合某个模式&#xff08;规则&#xff09;的文本。 正则表达式是一种对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些…

深度学习 - 42.特征交叉与 SetNET、Bilinear Interaction 与 FiBiNet

目录 一.引言 二.摘要 - ABSTRACT 三.介绍 - INTRODUCTION 四.相关工作 - RELATED WORK 1.因式分解机及其变体 - Factorization Machine and Its relevant variants 2. 基于深度学习的点击率模型 - Deep Learning based CTR Models 3.SENET Module 五.FiBiNet Model 1…

【C++】哈希的应用:位图和布隆过滤器

目录 1. 位图1.1 位图的概念1.2 位图的结构1.3 位图的实现 2. 布隆过滤器2.1 概念2.2 结构2.3 布隆过滤器的实现 1. 位图 1.1 位图的概念 &#x1f4ad;位图&#xff08;bitset&#xff09;是一种基于哈希思想设计的数据结构&#xff0c;其功能主要用于判断数据是否已存在。适…

来使用分支语句和循环语句实现一个小游戏吧(猜数字游戏)

猜数字游戏 1.代码展示2.菜单设计3.主函数部分3.随机数设计 所属专栏&#xff1a;C语言 博主首页&#xff1a;初阳785 代码托管&#xff1a;chuyang785 感谢大家的支持&#xff0c;您的点赞和关注是对我最大的支持&#xff01;&#xff01;&#xff01; 博主也会更加的努力&am…

rtthread默认网卡的操作

设置网卡优先级 在 RT-Thread 操作系统中&#xff0c;可以通过修改网卡的优先级来设置默认网卡。优先级越高的网卡会被优先选择为默认网卡。 下面介绍一些设置默认网卡优先级的方法&#xff1a; 在 RT-Thread 的网络配置文件 rtconfig.h 中&#xff0c;可以通过修改 NETIF_P…

Jmeter5.1.1报错:java.net.BindException: Address already in use: connect

Jmeter5.1.1报错&#xff1a;java.net.BindException: Address already in use: connect 原因&#xff1a;从网上找到资料&#xff1a;端口占用 Windows提供给TCP/IP链接的端口为 1024-5000&#xff0c;并且要四分钟来循环回收它们&#xff0c;就导致我们在短时间内跑大量的请…

把ChatGPT训练成你的得力助手

在调教chatgpt时&#xff0c;我们大部分的时候都需要一个好的学术翻译官&#xff0c;但是在他成为学术翻译官之前我们有很多规定要说明&#xff0c;比如不用回答我的问题&#xff0c;不用计算公式等。我将以下命令要求集成&#xff0c;在使用的时候只需要你发给它这段话&#x…

如何评估小程序开发费用:从项目规模到技术需求

作为一种越来越受欢迎的移动应用&#xff0c;小程序的开发费用是许多企业和个人考虑的重要因素之一。但是&#xff0c;要确定小程序开发费用并不是一件容易的事情&#xff0c;因为它涉及到多个因素&#xff0c;从项目规模到技术需求。 项目规模 小程序开发的费用通常与项目规…

Linux部署人大金仓(Kingbase8)

陈老老老板&#x1f9b8; &#x1f468;‍&#x1f4bb;本文专栏&#xff1a;国产数据库-人大金仓&#xff08;kingbase8&#xff09;&#xff08;主要讲一些人大金仓数据库相关的内容&#xff09; &#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下LInux上部署人大…

Vue+Echarts 项目演练(中)后台数据接口的创建

全局引用Echarts与axios 后台接口创建express路由 api接口数据创建 全局引用Echarts与axios vue3.0的挂载方式&#xff1a;使用Provide/Inject依赖注入&#xff0c;将替代vue2中在原型链上挂载一些属性在app.vue中使用provider来给后代们提供数据 <script> import { p…

经典数据结构之2-3树

2-3树定义 2-3树&#xff0c;是最简单的B-树&#xff0c;其中2、3主要体现在每个非叶子节点都有2个或3个子节点&#xff0c;B-树即是平衡树&#xff0c;平衡树是为了解决不平衡树查询效率问题&#xff0c;常见的二叉平衡书有AVL树&#xff0c;它虽然提高了查询效率&#xff0c…

深入JVM了解Java对象实例化过程

文章目录 一、对象创建方式二、对象产生步骤1、判断对象是否已经加载、链接、初始化2、为对象分配内存空间3、处理并发问题3.1 TLAB 4、初始化零值5、完善对象内存布局的信息6、调用对象的实例化方法 <init>7、总结 三、对象的内存布局1、对象头1.1 运行时元数据&#xf…

详解树与二叉树的概念,结构,及实现(上篇)

目录 一&#xff0c; 树 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二&#xff0c; 二叉树 2.1二叉树概念 三&#xff0c;特殊的二叉树 1. 满二叉树 2. 完全二叉树 3. 1 二叉树的性质 3. 2 二叉树的存储…

【速卖通】 AliExpress(速卖通)关键词搜索结果采集

采集场景 在AliExpress(速卖通) 首页中 http://www.aliexpress.com 中输入关键词&#xff0c;采集关键词搜索后得到的商品列表信息。 采集字段 关键词、标题、商品id、商品图片地址、商品详情链接、价格、免费退送货、星级、已出售数量、店铺名 采集结果 采集结果可导出为E…

Linux-初学者系列——篇幅7_文本编辑和处理命令

文本编辑和处理命令-目录 一、系统基本编辑命令安装vim软件工具包语法格式&#xff1a; 1、vim编辑命令模式01 普通模式02 编辑模式03 命令模式 2、编辑文件技巧01 批量删除多行指定信息02 批量增加多列指定信息03 编辑常见问题错误1&#xff1a;没有指定编辑信息错误2&#xf…

基于TensorRT的yolov5 实例分割部署

yolov5-7.0 github: https://github.com/ultralytics/yolov5/tree/master 1. 代码的使用 1.1 训练yolov5-seg模型 使用的yolov5-7.0的代码,github下载:https://github.com/ultralytics/yolov5/releases/tag/v7.0 训练指令 python segment/train.py --data coco128-seg.y…

centos7 查看服务器配置信息

1.linux查看版本当前操作系统发行信息 cat /etc/centos-release cat /etc/centos-release 2、查看内核版本uname -a或者cat /proc/version 3、查看CPU参数 1&#xff09;、查看 CPU 物理个数   grep physical id /proc/cpuinfo | sort -u | wc -l 2&#xff09;、查看 CPU …

SpringCloud:ElasticSearch之DSL查询文档

elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;一般测试用。例如…

magento webapi 接口返回 json对象

前言 现在主流的项目开发都是前后端分离&#xff0c;数据通过json对象格式进行传输。但是magento框架&#xff0c;和传统PHP框架相比&#xff0c;区别很大。虽然也支持以RestApi的形式传输数据&#xff0c;但是要么格式并非是传统jsonObject要么就是需要大量的get、set方法。本…