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 ...
随机推荐
- MinGW、Linux GNU、MSVC编译和链接动态库的分析
这几天研究CMake跨平台项目嘛,用了以下几种编译器: VS2019(MSVC) Linux GNU MinGW 编译之后发现链接动态库发现以下问题: VS2019中如果直接链接CMakeLists. ...
- py09函数简介
函数的返回值 # def func():# return 'asfjsfda'# res = func()# print(res) # 函数内要想返回给调用者值 必须用关键字return"& ...
- pip3 install
python3 -m venv tutorial-env source tutorial-env/bin/activatepip3 install *deactivate
- uniapp全局黑白
page{filter: grayscale(100%); } .uni-tabbar__item{filter: grayscale(100%); }
- 浅谈JS中的element.style和window.getComputedStyle()的区别
MDN对于element.style的解释 被高光的句子中的inline style属性是指css内联样式,即元素的style属性的属性值 总结一下,element.style只能获取到元素的styl ...
- OPENCV3 API
图像翻转 void flip(InputArray src, OutputArray dst, int flipCode); flipCode: 0: x 轴翻转 1: y 轴翻转 <0: x, ...
- Finance财务软件(月度结转专题)
支持按模板结转 默认结转模板 1.结转收入 借: 6001 主营业务收入 6051 其他业务收入 6301 营业外收入 贷: 4103 本年利润 2.结转成本.费用和税金 借: 4103 本年利润 贷 ...
- pdf在线预览 ng2-pdf-viewer的运用
angular项目在线预览PDF 1 安装 ng2-pdf-viewer yarn add ng2-pdf-viewer 2 在项目中添加 import { NgModule } from '@ang ...
- 2347. 最好的扑克手牌 (Easy)
问题描述 2347. 最好的扑克手牌 (Easy) 给你一个整数数组 ranks 和一个字符数组 suit .你有 5 张扑克牌,第 i 张牌大小为 ranks[i] ,花色为 suits[i] . ...
- QCheckBox CSS样式
QCheckBox:!hover { color:white; border-radius:10px; border:1px solid rgb(170, 170, 127); background- ...