Java实现简单的大顶堆

今天刷LeetCode的347. 前 K 个高频元素的时候使用到了优先队列,由于对大顶堆掌握不算熟练,于是写了一个简单大顶堆练手:
实现代码在最后

之前很少使用泛型来写代码,因此实现大顶堆的时候用到了泛型
public class MyMaxHeap<E>

选择采用数组来模拟大顶堆,则类中的私有属性有:

    //使用数组模拟完全二叉树
private Object [] data;
//数组的当前大小
private int size;
//数组的容量
private int capacity;
//比较器,比较器使用超类型限定符
private Comparator<? super E> comparator;

这里值得注意的是比较器的通配符类型使用的是超类型限定符:<? super E>

为什么使用超类型限定符?
由于我们要用到比较器的compare()方法,而该方法的两个参数应当是E或者E的超类,因此选择使用<? super E>.
关于类型通配符的详细介绍可看:
https://www.zhihu.com/question/20400700/answer/117464182

构造函数
构造函数只写了一个需要比较器的构造函数

 //带有比较器的构造函数
public MyMaxHeap(E[] data,Comparator<? super E> comparator){
this.data = data;
this.size=data.length;
this.capacity=size*2;
this.comparator=comparator;
//在利用已有数组进行构造的过程中要重新堆数组进行排列
//具体就是从最后一个节点的父节点向下筛选构建最大堆,一直到该节点前面的所有节点处理完毕
int temp=size-1;
while(temp>0) {
shiftUp(temp);
temp--;
}
}

向下构建最大堆的方法
向下构建最大堆就是不断交换该节点与该节点的最大的孩子节点,一直到没有孩子节点

public void shiftDown(int index){
//如果当前节点存在孩子节点
while(getLeftChildren(index)<size&&getLeftChildren(index)!=-1){
//获取当前节点的最大的孩子节点
int children=comparator.compare(
(E)data[getLeftChildren(index)],
(E)data[getRightChildren(index)]
)>0?getLeftChildren(index):getRightChildren(index); //交换当前节点与当前节点的孩子节点
swap(data,index,children); index=children;
}
}

向堆中插入数据
插入数据时如果需要扩容,这里只进行了1.5倍的简单扩容
插入数据的时候需要从插入数据的地方向上构建最大堆

public void insert (E num){
if(capacity<size){
//简单的扩容机制
capacity=capacity+capacity>>1;
data=Arrays.copyOf(data,capacity);
}
data[size]=num;
shiftUp(size);
size++;
}

向上构建最大堆

//将下标为index的数组元素向上移动
public void shiftUp(int index){
//使用Comparator进行比较当前的结点的数据与该节点的父节点的数据
while(index>0&&comparator.compare(
(E)data[index],(E)data[getParentIndex(index)])>0){
//如果父节点比当前节点小则交换位置
swap(data,index,getParentIndex(index));
index=getParentIndex(index);
System.out.println(index);
}
}

取出堆顶部数据
取出顶部数据之后将堆所在数组中最后一个元素放到堆顶,然后向下筛

 public E pollMax(){
E res=(E)data[0];
data[0]=data[--size];
shiftDown(0);
return res;
}

附上源码:
由于作者只是为了学习大顶堆,因此源码可能会有一定的纰漏,多多包涵

package com.edu.linear;

import org.junit.Test;

import java.util.*;

/**
* @author Sepnine
* @version 1.0
* @description: EODO
* @date 2022/10/2 8:26
*/
public class MyMaxHeap<E> {
//使用数组模拟完全二叉树
//使用Object数组是因为使用E[]作为类型的话无法进行初始化
//使用Object数组,然后在取出的时候再做强制类型转换
private Object [] data;
//数组的当前大小
private int size;
//数组的容量
private int capacity; //比较器,比较器使用超类型限定符
//该超类型限定符表示:泛型类型Comparator中只能使用E的超类
//超类型限定符可以作为方法的参数使用,但是不能作为方法的返回值
//子类型限定符可以作为方法的返回值,但是不能作为方法的参数
private Comparator<? super E> comparator; //构造函数
public MyMaxHeap(){
this.size=0;
this.data=new Object[20];
capacity=20;
}
public MyMaxHeap(E[] data) {
this.data = data;
this.size=data.length;
this.capacity=size*2;
int temp=size-1;
while(temp>0) {
shiftUp(temp);
}
} //带有比较器的构造函数
public MyMaxHeap(E[] data,Comparator<? super E> comparator){
this.data = data;
this.size=data.length;
this.capacity=size*2;
this.comparator=comparator;
//在利用已有数组进行构造的过程中要重新堆数组进行排列
//具体就是从最后一个节点的父节点向下筛选构建最大堆,一直到该节点前面的所有节点处理完毕
int temp=(size-1)/2;
while(temp>=0) {
shiftDown(temp);
temp--;
}
} /**
* @description: 检索最大堆的顶部
* @author Sepnine
* @date: 2022/10/2 11:29
*/
public E peekMax(){
return (E)data[0];
} /**
* @description: 检索并删除最大堆的顶部
* @author Sepnine
* @date: 2022/10/2 11:29
*/
public E pollMax(){
E res=(E)data[0];
data[0]=data[--size];
shiftDown(0);
return res;
} /**
* @description: 从堆的最后插入元素
* @author Sepnine
* @date: 2022/10/2 11:28
*/
public void insert (E num){
if(capacity<size){
//简单的扩容机制
capacity=capacity+capacity>>1;
data=Arrays.copyOf(data,capacity);
}
data[size]=num;
shiftUp(size);
size++;
} /**
* @description: 从指定下标向上筛(插入元素时使用)
* @author Sepnine
* @date: 2022/10/2 11:27
*/
@SuppressWarnings("unchecked")
//将下标为index的数组元素向上移动
public void shiftUp(int index){
//使用Comparator进行比较当前的结点的数据与该节点的父节点的数据
while(index>0&&comparator.compare(
(E)data[index],(E)data[getParentIndex(index)])>0){
//如果父节点比当前节点小则交换位置
swap(data,index,getParentIndex(index));
index=getParentIndex(index);
System.out.println(index);
}
} /**
* @description: 从指定下标向下筛(删除元素时使用)
* @author Sepnine
* @date: 2022/10/2 11:32
*/
public void shiftDown(int index){
while(getLeftChildren(index)<size&&getLeftChildren(index)!=-1){
//获取当前节点的最大的孩子节点
int children=comparator.compare(
(E)data[getLeftChildren(index)],
(E)data[getRightChildren(index)]
)>0?getLeftChildren(index):getRightChildren(index); //交换当前节点与当前节点的孩子节点
swap(data,index,children); index=children;
}
} /**
* @description: 获取父节点索引
* @author Sepnine
* @date: 2022/10/2 8:41
*/
public int getParentIndex(int index){
if(index==0){
return -1;
}
return (index-1)/2;
} //获取左孩子的索引
public int getLeftChildren(int parent){
return parent*2+1;
} //获取右孩子的索引
public int getRightChildren(int parent){
return parent*2+2;
} //交换数组元素
public void swap(Object[] data,int tmp1,int tmp2){
Object tmp=data[tmp1];
data[tmp1]=data[tmp2];
data[tmp2]=tmp;
} @Override
public String toString() {
StringBuilder res=new StringBuilder();
res.append("MyMaxHeap:{");
for(int i=0;i<size;i++){
res.append((E)data[i]).append(",");
}
res.append("}");
return res.toString();
} public static void main(String[] args){
Integer [] tmp=new Integer[]{0,12,3,24,124,22,89};
MyMaxHeap<Integer> myMaxHeap=new MyMaxHeap<>(tmp, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});
System.out.println(myMaxHeap); System.out.println(myMaxHeap.peekMax());
System.out.println(myMaxHeap);
System.out.println(myMaxHeap.pollMax());
System.out.println(myMaxHeap);
}
}

Java实现简单的大顶堆的更多相关文章

  1. 《排序算法》——堆排序(大顶堆,小顶堆,Java)

    十大算法之堆排序: 堆的定义例如以下: n个元素的序列{k0,k1,...,ki,-,k(n-1)}当且仅当满足下关系时,称之为堆. " ki<=k2i,ki<=k2i+1;或k ...

  2. Python使用heapq实现小顶堆(TopK大)、大顶堆(BtmK小)

    Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) | 四号程序员 Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) 4 Replies 需1求:给出N长 ...

  3. PriorityQueue实现大顶堆

    在做一道算法时需要使用大顶堆,所以查了一下记录. 使用PriorityQueue实现大顶堆 PriorityQueue默认是一个小顶堆,然而可以通过传入自定义的Comparator函数来实现大顶堆.如 ...

  4. 堆排序(大顶堆、小顶堆)----C语言

    堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...

  5. 剑指offer:数据流中的中位数(小顶堆+大顶堆)

    1. 题目描述 /** 如何得到一个数据流中的中位数? 如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值. 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两 ...

  6. heap c++ 操作 大顶堆、小顶堆

    在C++中,虽然堆不像 vector, set 之类的有已经实现的数据结构,但是在 algorithm.h 中实现了一些相关的模板函数.下面是一些示例应用 http://www.cplusplus.c ...

  7. 剑指Offer28 最小的K个数(Partition函数应用+大顶堆)

    包含了Partition函数的多种用法 以及大顶堆操作 /*********************************************************************** ...

  8. USACO Running Away From the Barn /// 可并堆 左偏树维护大顶堆

    题目大意: 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于m的点有多少个 左偏树 https://blog.csdn.net/pengwill97/article/details/82 ...

  9. 大顶堆与小顶堆应用---寻找前k小数

    vector<int> getLeastNumber(vector<int>& arr,int k){ vector<int> vec(k,); if(== ...

  10. 378. Kth Smallest Element in a Sorted Matrix(大顶堆、小顶堆)

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

随机推荐

  1. [Oracle19C ASM管理] 安装和配置ASM以及Oracle数据库

    一般设置 关闭防火墙 检查防火墙状态 systemctl status firewalld.service 暂时关闭防火墙,下次启动时防火墙仍随系统启动而启动 systemctl stop firew ...

  2. 使用myBadboy(python自主开发工具)启动谷歌浏览器并自动录制jmeter脚本

    一.源代码下载 https://gitee.com/rmtic/mybadboy 说明:因现有的录制方法有不能定制等不足之处,所以自力更生,自动生成对应jmeter脚本,减少维护成本 二.操作说明 1 ...

  3. 实验室服务器运维踩坑o.0

    先说背景:实验室新配了一台Dell T640服务器,双3090, 512G内存, 5 x 8T硬盘(RAID5),2 x 1T固态(RAID1),配置很够用但就是搭建运维踩了很多坑,以下是主要完成的几 ...

  4. RSTP-快速生成树协议

    1 STP的不足之处STP协议虽然能够解决环路问题,但是由于网络拓扑收敛慢,影响了用户通信质量. 2 RSTP概述RSTP在许多方面对STP进行了优化,它的收敛速度更快,而且能够兼容STP. 通过接口 ...

  5. debian/ubuntu下安装nodejs npm

    举例:在 /home 目录下 wget https://nodejs.org/dist/v16.17.1/node-v16.17.1-linux-x64.tar.xz nodejs官网下载地址,目前最 ...

  6. freeradius + mysql安装配置

    该文档参考http://t.zoukankan.com/FlyingPuPu-p-7772410.html安装,仅做了微调. 一.准备工作 安装编译FreeRadius所需要的依赖 #安装wget.g ...

  7. 【翻译】了解Flink-数据管道和ETL -- Learn Flink - Data Pipelines & ETL

    目录 无状态转换 map() flatmap() keyed 流 keyBy() keys计算 keyed流上的聚合 (Implicit)状态 reduce() 和其他聚合器 有状态的Transfor ...

  8. sap IUT255 Integration of SAP CRM and SAP IS-U_EN_Col62.pdf

    sap IUT255 Integration of SAP CRM and SAP IS-U_EN_Col62.pdf   sap IUT255 Integration of SAP CRM and ...

  9. Finance财务软件(如何运行该软件)

    下载软件 首先,去gitHub下载该项目的release,尽量下载最新版本:https://github.com/edwardorchis/finance/releases.国内也可以在码云下载htt ...

  10. Linux下如何排查CPU及内存占用过多

    CPU 使用top命令,然后按shift+p按照CPU排序,找到占用CPU过高的进程pid. 使用top -H -p pid命令,找到进程中消耗资源最高的线程ppid. 使用echo 'obase=1 ...