堆排序算法Java实现
摘要 介绍堆排序的基本概念及其实现。
前言
排序大的分类可以分为两种:内排序和外排序。在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序。这里讲的排序是内排序中的堆排序算法,它属于选择排序的一种。
堆排序和插入排序一样,是一种就地排序算法(不需要额外的存储空间)。堆是一种数据结构,它可以被视为一种完全二叉树。最小堆又叫小顶堆,满足小顶堆的条件是每个孩子节点的值都大于父节点。大顶堆则相反。
源码
import java.util.Arrays;
public class HeapSort {
//使用数组存储堆中的数据
private int[] data;
public static void main(String[] args) {
int[] a = {1, 50, 38, 78, 33, 12, 65, 97, 76, 13, 27, 32, 50, 63, 101};
int lastIndex = a.length - 1;
//循环建堆
for (int i = 0; i < lastIndex; i++) {
//建堆
buildMaxHeap(a, lastIndex - i);
//交换堆顶和最后一个元素
swap(a, 0, lastIndex - i);
System.out.println("第" + i + "次遍历,执行结果:" + Arrays.toString(a));
}
}
/**
* 对data数组从0到 lastIndex 建大顶堆
*/
public static void buildMaxHeap(int[] data, int lastIndex) {
//从lastIndex节点(最后一个节点)的父节点开始
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
//k保存正在判断的节点
int k = i;
//如果当前k节点的子节点存在
while (k * 2 + 1 <= lastIndex) {
//k节点的左子节点的下标
int biggerIndex = left(k);
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if (biggerIndex < lastIndex) {
//若右子节点的值较大
if (data[biggerIndex] < data[biggerIndex + 1]) {
//biggerIndex总是记录较大子节点的下标
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if (data[k] < data[biggerIndex]) {
//交换它们
swap(data, k, biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k = biggerIndex;
} else {
break;
}
}
}
}
/**
* 根据父节点下标获取左孩子节点下标
*
* @param index 下标
* @return 2 * index + 1
*/
private static int left(int index) {
// 左移1位相当于乘2
return (index + 1) << 1 - 1;
}
//交换
private static void swap(int[] data, int i, int j) {
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
基于Top k的最小堆算法
/**
* 最小堆
*
*/
public class MinHeap {
//使用数组存储堆中的数据
private int[] data;
public MinHeap(int[] data) {
this.data = data;
bulidHeap();
}
/**
* 建立最小堆
*/
private void bulidHeap() {
for (int i = (data.length) / 2 - 1; i >= 0; i--) {//下标小于等于i的节点拥有子节点
change(i);
}
}
/**
* 根据父节点判断是否
* 与左右孩子交换
*
* @param i
*/
private void change(int i) {
int temp = 0;
int left = left(i);
int right = right(i);
//存在右节点则存在左节点
if (right < data.length) {
//拿到左右孩子中小的下标
temp = min(left, right);
if (data[i] > data[temp]) {
swap(i, temp);
//如果和子节点发生交换,则要对子节点的左右孩子进行调整
change(temp);
}
} else if (right < data.length) {
//不存在右节点但存在左节点,则左节点无孩子节点
if (data[i] > data[left])
swap(i, left);
//孩子节点大于父节点,直接交换位置
}
}
/**
* 获取两个节点中较小的节点的下标
*
* @param i
* @param j
* @return
*/
private int min(int i, int j) {
if (data[i] >= data[j])
return j;
return i;
}
/**
* 根据父节点下标获取
* 左孩子节点下表
*
* @param i
* @return
*/
private int left(int i) {
return ((i + 1) << 1) - 1;
}
/**
* 根据父节点下表获取
* 右孩子节点下标
*
* @param i
* @return
*/
private int right(int i) {
return (i + 1) << 1;//左移1位相当于乘2
}
/**
* 根据下标交换数组中的位置
*
* @param i
* @param j
*/
private void swap(int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
/**
* 重置堆顶
*
* @param root
*/
public void newRoot(int root) {
data[0] = root;
change(0);
}
/**
* 获取堆顶
*
* @return
*/
public int getRoot() {
return data[0];
}
/**
* 获取堆数据
*/
public int[] getData() {
return data;
}
}
实战
小顶堆和大顶堆对于解决TOP-K问题拥有较高的效率,在N个数中找到K(K<N)个最大或最小的数可以分别使用小顶堆算法和大顶堆算法。下面我用上面的小顶堆算法找出一个数组中最大的7个数。
public class TopK {
public static void main(String[] args) {
int[] num = {1, 3, 6, 7, 332, 355, 11, 325, 63, 25, 75, 32, 393, 759};
int[] data = {1, 3, 6, 7, 332, 355, 11};//取前7个数据建立最小堆
MinHeap heap = new MinHeap(data);
for (int i = 7; i < num.length; i++) {
//循环与堆顶比较,大于于堆顶则重置堆顶
if (num[i] > heap.getRoot()) {
heap.newRoot(num[i]);
}
}
//循环输出前7个最大的数
for (int n : heap.getData()) {
System.out.println(n);
}
}
}
测试结果如下所示:
63
325
75
393
332
355
759
小结
对于Wiener以上的话题,大家又有什么自己的独特见解呢?欢迎在下方评论区留言!
Reference
堆排序算法Java实现的更多相关文章
- 堆排序算法 java 实现
堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...
- 排序系列 之 堆排序算法 —— Java实现
基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...
- 堆排序算法(Java实现)
将待排序的序列构造成一个大顶堆(从大到小排要构造成小顶堆).此时,整个序列的最大值就是堆顶的根节点,将他和末尾元素交换,然后将剩余的length-1个节点序列重新构造成新的堆.重复执行,便能得到一个有 ...
- 算法-java代码实现堆排序
堆排序 第7节 堆排序练习题 对于一个int数组,请编写一个堆排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例: [1,2,3,5,2,3],6 [1,2 ...
- 堆排序算法的java实现
堆积排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素.堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O ...
- 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解
一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...
- 排序算法入门之堆排序(Java实现)
堆排序 在学习了二叉堆(优先队列)以后,我们来看看堆排序.堆排序总的运行时间为O(NlonN). 堆的概念 堆是以数组作为存储结构. 可以看出,它们满足以下规律: 设当前元素在数组中以R[i]表示,那 ...
- 【java排序】 归并排序算法、堆排序算法
一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...
- 八大排序算法Java实现
本文对常见的排序算法进行了总结. 常见排序算法如下: 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 它们都属于内部排序,也就是只考虑数据量较小仅需要使用内存的排 ...
- 排序算法(Java实现)
这几天一直在看严蔚敏老师的那本<数据结构>那本书.之前第一次学懵懵逼逼,当再次看的时候,发觉写的是非常详细,非常的好. 那就把相关的排序算法用我熟悉的Java语言记录下来了.以下排序算法是 ...
随机推荐
- 面试题53 - I. 在排序数组中查找数字 I
地址:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/ <?php /** 面试题53 ...
- 一个生成随机颜色的js函数
function getRandomColor(){ let rgb = []; for(let i=0;i<3;++i){ let color = Math.floor(Math.random ...
- Visio绘制时间轴安排图的方法
本文介绍基于Visio软件绘制时间轴.日程安排图.时间进度图等的方法. 在很多学习.工作场合中,我们往往需要绘制如下所示的一些带有具体时间进度的日程安排.工作流程.项目进展等可视化图表. ...
- js发送get 、post请求
前言 我们经常会用到js发送网络请求,这里用到XMLHttpRequest,主要是为了考虑早期的IE.分为三步:创建需要的对象.连接和发送.接收. GET请求 var httpRequest = ne ...
- linux下npm安装的全局命令无法执行
npm install laravel-echo-server -g 安装了之后在其他目录无法执行,找不到命令,在windows下可以直接使用,在linux下需要配置下环境变量 npm prefix ...
- Linux基础知识之:crontab定时任务
目录 5.3 定时(计划)任务crontab 5.3.1 定时任务的概念 5.3.2 定时任务的作用 5.3.3 crontab命令语法 5.3.4. crontab编辑语法 5.4.5 定时任务的编 ...
- oracle数据库体系架构详解
在学习oracle中,体系结构是重中之重,一开始从宏观上掌握它的物理组成.文件组成和各种文件组成.掌握的越深入越好.在实际工作遇到疑难问题,其实都可以归结到体系结构中来解释.体系结构是对一个系统的框架 ...
- cxDBTreeList:最简单的节点图标添加方法
先在窗体上放ImageList关联到cxDBTreeList,在cxDBTreeList的GetNodeImageIndex事件中写如下: procedure cxDBTreeList1GetNode ...
- CompletableFuture原理及应用场景详解
1.应用场景 现在我们打开各个APP上的一个页面,可能就需要涉及后端几十个服务的API调用,比如某宝.某个外卖APP上,下面是某个外卖APP的首页.首页上的页面展示会关联很多服务的API调用,如果使用 ...
- 【软件】Rhythmbox播放器调节音量
Rhythmbox播放器调节音量 零.起因 最近换了Ubuntu系统,在写代码时想听歌,故使用Rhythmbox播放器播放一些mp3文件,但同时又要看教程,希望音乐声音小一点,但是找来找去都没有发现R ...