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 ...
随机推荐
- corkscrew在ssh中发生错误
使用绝对路径 ProxyCommand="corkscrew 127.0.0.1 12345 jump.123.com 2020" abc@efg.com 改为 ProxyComm ...
- Linux的stat命令结果说明
There are 3 kind of "timestamps": Access - the last time the file was read Modify - the la ...
- STM32F0使用LL库实现UART接收
初始化: 1 void MX_USART1_UART_Init(void) 2 { 3 4 /* USER CODE BEGIN USART1_Init 0 */ 5 6 /* USER CODE E ...
- MVP模式(转)
什么是MVP模式? 这个MVP可不是腾讯游戏<王者荣耀>中的MVP.我们今天要讨论的MVP其实同MVC一样,是一种编程模式和思想,也许更准确地讲是一种架构. MVP和MVC的区别 ...
- JDK、JRE、JVM和i++
JRE:运行环境(包含JVM和JAVA核心类库) JDK:JAVA开发工具包(包含JRE和开发工具)----开发工具:指编译工具javac和运行工具java JVM:虚拟机,保证了跨平台 ++i:先运 ...
- vue v-for 使用
html <div> <el-button @click="addListItem" type="primary" style="p ...
- maven概述,maven依赖管理的概念,maven一键构建概念
maven概述 Maven在美国是一个口语化的词语,代表专家,内行的意思 一个对Maven比较正式的定义是这么说的,Maven是一个项目管理工具,它包含了一个项目对象模型(POM:Project O ...
- iview table配合Tooltip使用的时候 气泡错位的问题
Tooltip 气泡错位 点击table的单元格,实现遮盖文字的预览功能,但是气泡会发生偏移,看了Tooltip的样式发现 气泡是绝对定位, 想到子绝父相,于是给表格的td添加相对定位的功能,结果能解 ...
- 微信防红页面JS代码
将Js代码复制粘贴到你网站所需要的页面,保存即可,完美实现防红,具体未测试,如果需要可以自己测试效果. <meta charset="utf-8″> <meta name= ...
- mac_office2019
mac_office2019下载 1,链接地址: mac_office2019: https://590m.com/d/28636472-44062040-dc385f (访问密码:7410) 2, ...