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. corkscrew在ssh中发生错误

    使用绝对路径 ProxyCommand="corkscrew 127.0.0.1 12345 jump.123.com 2020" abc@efg.com 改为 ProxyComm ...

  2. Linux的stat命令结果说明

    There are 3 kind of "timestamps": Access - the last time the file was read Modify - the la ...

  3. STM32F0使用LL库实现UART接收

    初始化: 1 void MX_USART1_UART_Init(void) 2 { 3 4 /* USER CODE BEGIN USART1_Init 0 */ 5 6 /* USER CODE E ...

  4. MVP模式(转)

    什么是MVP模式?     这个MVP可不是腾讯游戏<王者荣耀>中的MVP.我们今天要讨论的MVP其实同MVC一样,是一种编程模式和思想,也许更准确地讲是一种架构. MVP和MVC的区别  ...

  5. JDK、JRE、JVM和i++

    JRE:运行环境(包含JVM和JAVA核心类库) JDK:JAVA开发工具包(包含JRE和开发工具)----开发工具:指编译工具javac和运行工具java JVM:虚拟机,保证了跨平台 ++i:先运 ...

  6. vue v-for 使用

    html <div> <el-button @click="addListItem" type="primary" style="p ...

  7. maven概述,maven依赖管理的概念,maven一键构建概念

    maven概述 Maven在美国是一个口语化的词语,代表专家,内行的意思 一个对Maven比较正式的定义是这么说的,Maven是一个项目管理工具,它包含了一个项目对象模型(POM:Project  O ...

  8. iview table配合Tooltip使用的时候 气泡错位的问题

    Tooltip 气泡错位 点击table的单元格,实现遮盖文字的预览功能,但是气泡会发生偏移,看了Tooltip的样式发现 气泡是绝对定位, 想到子绝父相,于是给表格的td添加相对定位的功能,结果能解 ...

  9. 微信防红页面JS代码

    将Js代码复制粘贴到你网站所需要的页面,保存即可,完美实现防红,具体未测试,如果需要可以自己测试效果. <meta charset="utf-8″> <meta name= ...

  10. mac_office2019

    mac_office2019下载 1,链接地址: mac_office2019: https://590m.com/d/28636472-44062040-dc385f (访问密码:7410) 2, ...