摘要 介绍堆排序的基本概念及其实现。

前言

  排序大的分类可以分为两种:内排序和外排序。在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序。这里讲的排序是内排序中的堆排序算法,它属于选择排序的一种。

  堆排序和插入排序一样,是一种就地排序算法(不需要额外的存储空间)。堆是一种数据结构,它可以被视为一种完全二叉树。最小堆又叫小顶堆,满足小顶堆的条件是每个孩子节点的值都大于父节点。大顶堆则相反。

源码

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实现的更多相关文章

  1. 堆排序算法 java 实现

    堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...

  2. 排序系列 之 堆排序算法 —— Java实现

       基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...

  3. 堆排序算法(Java实现)

    将待排序的序列构造成一个大顶堆(从大到小排要构造成小顶堆).此时,整个序列的最大值就是堆顶的根节点,将他和末尾元素交换,然后将剩余的length-1个节点序列重新构造成新的堆.重复执行,便能得到一个有 ...

  4. 算法-java代码实现堆排序

    堆排序 第7节 堆排序练习题 对于一个int数组,请编写一个堆排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例: [1,2,3,5,2,3],6 [1,2 ...

  5. 堆排序算法的java实现

         堆积排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素.堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O ...

  6. 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  7. 排序算法入门之堆排序(Java实现)

    堆排序 在学习了二叉堆(优先队列)以后,我们来看看堆排序.堆排序总的运行时间为O(NlonN). 堆的概念 堆是以数组作为存储结构. 可以看出,它们满足以下规律: 设当前元素在数组中以R[i]表示,那 ...

  8. 【java排序】 归并排序算法、堆排序算法

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  9. 八大排序算法Java实现

    本文对常见的排序算法进行了总结. 常见排序算法如下: 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 它们都属于内部排序,也就是只考虑数据量较小仅需要使用内存的排 ...

  10. 排序算法(Java实现)

    这几天一直在看严蔚敏老师的那本<数据结构>那本书.之前第一次学懵懵逼逼,当再次看的时候,发觉写的是非常详细,非常的好. 那就把相关的排序算法用我熟悉的Java语言记录下来了.以下排序算法是 ...

随机推荐

  1. php连接sql server 2014踩坑及处理记录

    1.PDOException: SQLSTATE[42S02]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]对象名 'dbotest' ...

  2. 【ABAQUS Material】density 行为

    1.overview 进行eigenfrequency . transient dynamic analysis. transient heat transfer analysis. adiabati ...

  3. kafka开启kerberos认证详细步骤

    一.kerberos安装部署 kerberos的基本原理不做过多介绍了,可自行查阅:本文主要介绍kerberos的安装及使用;使用到的软件版本:系统:Red Hat Enterprise Linux ...

  4. iterm2配置ssh自动登录

    iterm2 ssh 演示 cmd + o 打开服务器列表,方向键选择要登录的机器,回车,提示输入密码: option + cmd + f 打开密码管理器,方向键选择密码,回车,即可登录:(这一步通过 ...

  5. centos安装php环境

    安装 PHP 所需扩展 yum install libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcur ...

  6. 使用Istio灰度发布

    目录 灰度发布 1. Istio 1.1 Istio介绍 1.2 Istio是如何工作的 2. 安装Istio 2.1 环境 2.2 得到二进制文件 2.3 安装istio 3. 部署bookinfo ...

  7. Java工程师应该掌握的知识

    https://pan.baidu.com/s/1pXKwwVwE_g9RhjGrbABcUAydvn 以Java工程师应该掌握的知识,按重要程度排出六个梯度: 第一梯度:计算机组成原理.数据结构和算 ...

  8. md语法练手随笔

    代码 单行代码:代码之间分别用一个反引号包起来 代码块: 代码之间分别用三个反引号包起来, 且两边的反引号单独占一行 这是一级标题 这是六级标题 这是加粗的文字 这是倾斜的文字 这是斜体加粗的文字 这 ...

  9. sql server2008r2其中一张表不能任何操作

    用户的数据库一张高频表,使用select count(*) from t1 竟然一直在转圈,显示开始,而没有end. 找尽原因不得果.把数据库备份后在恢复,可以使用几小时,之后又是老毛病抽风. 用户生 ...

  10. opencv的学习记录(python)

    作为最容易上手之一的语言,python拥有着大量的第三方库,这些第三方库的存在使得很多人可以专注于业务逻辑.数学逻辑而忽略繁琐的代码操作,python的opencv第三方库就是其中之一. 一.第三方库 ...