Java实现简单的大顶堆
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实现简单的大顶堆的更多相关文章
- 《排序算法》——堆排序(大顶堆,小顶堆,Java)
十大算法之堆排序: 堆的定义例如以下: n个元素的序列{k0,k1,...,ki,-,k(n-1)}当且仅当满足下关系时,称之为堆. " ki<=k2i,ki<=k2i+1;或k ...
- Python使用heapq实现小顶堆(TopK大)、大顶堆(BtmK小)
Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) | 四号程序员 Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) 4 Replies 需1求:给出N长 ...
- PriorityQueue实现大顶堆
在做一道算法时需要使用大顶堆,所以查了一下记录. 使用PriorityQueue实现大顶堆 PriorityQueue默认是一个小顶堆,然而可以通过传入自定义的Comparator函数来实现大顶堆.如 ...
- 堆排序(大顶堆、小顶堆)----C语言
堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...
- 剑指offer:数据流中的中位数(小顶堆+大顶堆)
1. 题目描述 /** 如何得到一个数据流中的中位数? 如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值. 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两 ...
- heap c++ 操作 大顶堆、小顶堆
在C++中,虽然堆不像 vector, set 之类的有已经实现的数据结构,但是在 algorithm.h 中实现了一些相关的模板函数.下面是一些示例应用 http://www.cplusplus.c ...
- 剑指Offer28 最小的K个数(Partition函数应用+大顶堆)
包含了Partition函数的多种用法 以及大顶堆操作 /*********************************************************************** ...
- USACO Running Away From the Barn /// 可并堆 左偏树维护大顶堆
题目大意: 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于m的点有多少个 左偏树 https://blog.csdn.net/pengwill97/article/details/82 ...
- 大顶堆与小顶堆应用---寻找前k小数
vector<int> getLeastNumber(vector<int>& arr,int k){ vector<int> vec(k,); if(== ...
- 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 ...
随机推荐
- thirty-one
动态组件 动态切换组件的显示和隐藏 如何实现动态组件的渲染 vue提供了有一个内置的<component>组件,专门用来实现动态组件的渲染.示例代码如下: 使用keep-alive保持状态 ...
- Twenty-seven
侦听器 watch侦听器 watch侦听器允许开发者监视数据 的变化,从而针对数据的变化做特定的操作 语法如下 侦听器的格式 1.方法格式的侦听器 缺点:无法在所进入页面的时候,自动触发!!! ...
- smartgit 安装
下载 https://www.syntevo.com/smartgit/download/ 破解删掉
- 关于活动目录AD(域)的相关配置(已更新8.31)
关于活动目录AD(域)的相关配置 目录 一. 配置Server2019升级活动目录AD 1 二. 配置活动目录AD内的文件服务器 13 三. 配置活动目录AD域内分发软件 ...
- Oracle 存储过程4:PL/SQL动态执行DDL语句
- R语言3D图导出矢量图有bug
谁不喜欢高清无码?rgl.snapshot就是个渣渣 首先,用rgl画3D图并调整好视角,代码如下: z <- 2 * volcano # Exaggerate the reliefx < ...
- PO 锁
SAP NetWeaver Administrator->可用性和监控->资源监控->锁
- element-ui的自定义表头
自定义表头 需求:之前在做一个项目的时候,原型图要求表头文字需要额外解释就会在文字后面标注 1,2作为上标 html中提供了<sup></sup>和<sub>< ...
- redis过期数据的底层存储结构
- OPENGL入门的小知识点
记录一下看到的知识点. 大部分知识点来自于https://learnopengl-cn.github.io/ 1.什么是OpenGL 一般它被认为是一个API,包含了一系列可以操作图形.图像的函数.然 ...