个人博客地址:http://kyle.org.cn/2018/03/13/heapsort/

Java实现泛型堆排算法,用于N个对象中选择最大或者最小的前M个,其中M<=N

类似于Mysql中order by + limit的功能,如果有类似场景的需求,可以直接拷贝到项目中使用

Github源码地址:https://github.com/Kyle-Wilson1/Algorithm_Java/tree/master/heapsort

工程目录结构

  • BootStrap:启动类,测试入口
  • Node:排序的对象
  • AbstractHeapObject:对象需要实现的接口
  • HeapDirectionEnum:堆方向枚举
  • HeapSort:堆排算法实现类
  • HomeController:web api测试

启动类

  • 作为程序的入口,写了一些测试数据
public class BootStrap {

    public static void main(String[] args) {
new BootStrap().handle();
} private void handle() {
HeapSort<Node> heapSort = new HeapSort<>(); List<Node> arr = new ArrayList<>(Arrays.asList(
new Node(1L, 1L),
new Node(2L, 2L),
new Node(1L, 1L),
new Node(2L, 2L),
new Node(3L, 3L),
new Node(4L, 4L)));
heapSort.setDirection(HeapDirectionEnum.MAX_ROOT);
heapSort.setHeapCapability(5);
heapSort.buildHeap(arr); heapSort.getHeap().forEach(System.out::println); List<Node> arr1 = new ArrayList<>(Arrays.asList(
new Node(1L, 1L),
new Node(2L, 2L),
new Node(3L, 3L),
new Node(4L, 4L),
new Node(5L, 5L)));
heapSort.buildHeap(arr1);
System.out.println("insert arr1:"); heapSort.getHeap().forEach(System.out::println);
System.out.println("pop: " + heapSort.heapPop());
}
}

测试结果如下:

Node{key=3, value=3}

Node{key=2, value=2}

Node{key=1, value=1}

Node{key=1, value=1}

Node{key=2, value=2}

insert arr1:

Node{key=2, value=2}

Node{key=2, value=2}

Node{key=1, value=1}

Node{key=1, value=1}

Node{key=1, value=1}

pop: Node{key=2, value=2}

定义对象接口

  • 对于要排序的对象,必须先实现该接口
  • getKey()返回某一个对象要用于排序的字段
public abstract class AbstractHeapObject {

    public abstract Long getKey();

}

排序对象

  • 待排序的类实现,需要实现AbstractHeapObject接口
public class Node extends AbstractHeapObject {

    private Long key;
private Long value; public Node(Long key, Long value) {
this.key = key;
this.value = value;
} @Override
public Long getKey() {
return key;
} public Long getValue() {
return value;
} @Override
public String toString() {
return "Node{" +
"key=" + key +
", value=" + value +
'}';
}
}

定义堆排方向枚举

  • 大根堆,适用于N个数中求最小的前M个数
  • 小根堆,适用于N个数中求最大的前M个数
public enum HeapDirectionEnum {

    //大根堆,适用于N个数中求最小的前M个数
MAX_ROOT(0, "MAX_ROOT", "大根堆"),
//小根堆,适用于N个数中求最大的前M个数
MIN_ROOT(1, "MIN_ROOT", "小根堆"); private Integer id;
private String name;
private String remark; HeapDirectionEnum(Integer id, String name, String remark) {
this.id = id;
this.name = name;
this.remark = remark;
} public Integer getId() {
return id;
} public String getName() {
return name;
} public String getRemark() {
return remark;
}
}

堆排核心算法

  • 堆的向上调整,向下调整,弹出堆等实现
public class HeapSort<T extends AbstractHeapObject> {

    private List<T> sourceData;
private HeapDirectionEnum direction;
private List<T> heap;
private int heapCapability; public void setDirection(HeapDirectionEnum direction) {
this.direction = direction;
} public void setHeapCapability(int heapCapability) {
this.heapCapability = heapCapability;
} public List<T> getHeap() {
return heap;
} synchronized public void buildHeap(List<T> sourceData) { this.sourceData = sourceData; //初始化堆容量
if (heap == null) {
heap = new ArrayList<>(heapCapability);
} sourceData.forEach(x -> {
//如果堆中元素还没有达到最大值,则插入到堆尾并向上调整,否则替换根元素并向下进行调整
if (heap.size() < heapCapability) {
heapUp(x);
} else {
if (direction == HeapDirectionEnum.MAX_ROOT && x.getKey() < heap.get(0).getKey()
|| direction == HeapDirectionEnum.MIN_ROOT && x.getKey() > heap.get(0).getKey()) {
heap.set(0, x);
heapDown(0);
}
}
}); } /**
* @param current the value to be added at the tail
*/
private void heapUp(T current) {
int i, j;
heap.add(current);
i = heap.size() - 1;
j = (i - 1) / 2; //j指向i的父结点 while (i > 0) {
if (direction == HeapDirectionEnum.MAX_ROOT && heap.get(j).getKey() >= current.getKey()
|| direction == HeapDirectionEnum.MIN_ROOT && heap.get(j).getKey() <= current.getKey()) {
break;
}
heap.set(i, heap.get(j));
i = j;
j = (i - 1) / 2;
}
heap.set(i, current);
} /**
* @param top the location where the value will be adjusted down
*/
private void heapDown(int top) {
int j = 2 * top + 1;
T x = heap.get(top);
int heapSize = heap.size() - 1; while (j <= heapSize) {
if (j + 1 <= heapSize && (
direction == HeapDirectionEnum.MAX_ROOT && heap.get(j + 1).getKey() > heap.get(j).getKey()
|| direction == HeapDirectionEnum.MIN_ROOT && heap.get(j + 1).getKey() < heap.get(j).getKey()))
j++;
if (direction == HeapDirectionEnum.MAX_ROOT && heap.get(j).getKey() <= x.getKey()
|| direction == HeapDirectionEnum.MIN_ROOT && heap.get(j).getKey() >= x.getKey()) {
break;
}
heap.set(top, heap.get(j));
top = j;
j = 2 * top + 1;
}
heap.set(top, x);
} public T heapPop() {
T ret = heap.get(0); heap.set(0, heap.get(heap.size() - 1));
heap.remove(heap.size() - 1);
heapDown(0); return ret;
} }

造轮子-Java泛型堆排的更多相关文章

  1. 别在重复造轮子了,几个值得应用到项目中的 Java 开源库送给你

    我是风筝,公众号「古时的风筝」.文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面.公众号回复『666』获取高清大图. 风筝我作为一个野路子开发者,直到 ...

  2. java 堆排,优先级队列,归并排序

    堆排 堆排是基于二叉树而得来的 例如:对一个数组 可以转为二叉树:       二叉树特性父节点为 i ,  左叶子节点为2i+1:右叶子节点为2i+2; 步骤分解: 1. 先从第一个非叶子节点(即下 ...

  3. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  4. Java泛型总结

    1. 什么是泛型?泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的 ...

  5. Java泛型学习笔记--Java泛型和C#泛型比较学习(一)

    总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...

  6. 自己造轮子系列之OOM框架AutoMapper

    [前言] OOM框架想必大家在Web开发中是使用频率非常之高的,如果还不甚了解OOM框架,那么我们对OOM框架稍作讲解. OOM顾名思义,Object-Object-Mapping实体间相互转换.常见 ...

  7. 除非你是BAT,前端开发中最好少造轮子

    站在前人的肩膀上 HTML.CSS.JavaScript是前端的根基,这是无可否认的事实.正如一辆车当然都是由一堆钢板和螺钉组成的,但是现在还有人拎着个锤子敲敲打打的造车吗?李书福说过,“汽车不过是四 ...

  8. JAVA 泛型意淫之旅(二)

    编译器如何处理泛型 泛型类编译后长什么样? 接上文,JAVA 泛型意淫之旅1,成功迎娶白富美后,终于迎来了最振奋人心的一刻:造娃!造男娃还是造女娃?对于我们程序猿来说,谁还在乎是男娃女娃,只要是自己的 ...

  9. java数据结构----堆

    1.堆:堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了.当速度很重要且有很多插入操作时,可以选择堆 ...

随机推荐

  1. ORACLE中修改表的Schema的总结

    前阵子遇到一个案例,需要将数据库中的几个表从USER A 移动到USER B下面,在ORACLE中,这个叫做更改表的所有者或者修改表的Schema.其实遇到这种案例,有好几种解决方法.下面我们通过实验 ...

  2. asp.mvc中的vue分页实例,分页组件无法重置reload,解决点击查询按钮后,分页不刷新的问题

    刚刚接触Vue.js,现在需要做一个查询功能,并且进行服务端分页.主要思路是在页面中注册一个分页组件,然后进行调用.代码如下 1.引用vue.js,具体去网上下载 2.在html的body中添加如下代 ...

  3. java 学习第二天小练习

    1.从控制台输入学员王浩3门课程成绩,编写程序实现 ChengJi (1)数学课和英语课的分数之差 (2)3门课的平均分 代码如下: p.p1 { margin: 0.0px 0.0px 0.0px ...

  4. TCP为何采用三次握手来建立连接,若采用二次握手可以吗

    1. TCP简介 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接(连接导向)的.可靠的.基于IP的传输层协议,采用三次握手确认建立一个连接. TCP为 ...

  5. freemarker中的substring取子串

    freemarker中的substring取子串 1.substring取子串介绍 (1)表达式?substring(from,to) (2)当to为空时,默认的是字符串的长度 (3)from是第一个 ...

  6. Jquery常用操作:checkbox、select取值,radio、checkbox、select选中及其相关

    常用Jquery操作:checkbox取值.select取值.radio选中.checkbox选中.select选中及其相关: 1.影藏页面元素 使用jquery真的很方便,比如要控制div的显示与隐 ...

  7. Vue安装依赖npm install时报错问题解决方法

    1.vue的安装依赖于node.js,要确保你的计算机上已安装过node.js.    可进入cmd编辑器,输入命令 node -v进行查看.出现版本信息即成功!没有则从浏览器上面下载安装即可,没有安 ...

  8. wireshark抓包看ECN

    由于实验需要,要统计ECN信息.为了验证拓扑中是否真的有ECN信息,用了wireshark进行抓包查看. 网上找到的相关有用资料有:http://blog.csdn.net/u011414200/ar ...

  9. Linux tar包安装Nginx-1.7.6 (yum方式安装依赖)

    1.首先安装依赖包(依赖包有点多,我们采用yum的方式来安装) yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel ...

  10. heartbeat单独提供高可用服务

    本文目录:1.简介2.安装heartbeat 2.1 编译安装Heartbeat3.heartbeat相关配置文件 3.1 配置文件ha.cf 3.2 配置文件authkeys 3.3 配置文件har ...