堆是具有以下性质的完全二叉树,每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子:

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

ok,了解了这些定义。接下来,我们来看看堆排序的基本思想及基本步骤:

1、基本思想

将待排序序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根节点,将其与末尾元素进行交换,此时末尾为最大值。然后将剩余n-1个元素重新构造成一个堆,堆顶继续为n-1个元素的最大值,然后再将其与倒数第二位的元素交换。如此反复执行,便能得到一个有序序列。

2、算法描述

(1) 构造初始堆,将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。

假设给定无序序列结构如下:

4 6 8 5 9 

此时我们从最后一个非叶子结点开始,顺序从下至上(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,索引1对应的值是6),从左至右,从下至上进行调整。

找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

9与4交换之后,该子树[4, 5, 6]为非大顶堆,需要调整为大顶堆,[4, 5 ,6]中6最大,交换4和6。

此时,我们就将一个无需序列构造成了一个大顶堆。每个非叶子节点i 都满足:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

(2) 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与倒数第二元素交换,得到第二大元素。如此反复进行交换、重建、交换。

重新调整剩余n-1个元素的结构,使其继续满足大顶堆排序

再将堆顶元素8与倒数第二元素5进行交换,得到第二大元素8

继续进行调整、交换,如此反复进行,最终使得整个序列有序

再简单总结堆排序的基本思路:
(1) 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
(2) 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
(3) 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

3、代码实现

public class HeapSort {

    public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
//int[] array = new int[]{10, 1, 9, 2, 8, 3, 7, 4, 6, 5};
int[] array = new int[100000];
for (int i = 0; i < 100000; i++) {
array[i] = (int) (Math.random() * 100000);
}
heapSort(array);
Long endTime = System.currentTimeMillis();
System.out.println((endTime - startTime) + " " + array.length);
} /**
* 堆排序
*
* @param array
*/
public static void heapSort(int[] array) {
// 构建大顶堆
int len = array.length;
for (int i = len / 2 - 1; i >= 0; i--) {
adjustHeap(array, i, len);
} for (int j = len - 1; j > 0; j--) {
// 将顶上元素与最后元素交换,即最大的元素存放最后
swap(array, 0, j);
// 对剩下的j 个元素继续构建大顶堆
adjustHeap(array, 0, j);
//System.out.println(Arrays.toString(array));
} } /**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
*
* @param array
* @param i
* @param length
*/
public static void adjustHeap(int[] array, int i, int length) {
int temp = array[i];
for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
if (k + 1 < length && array[k] < array[k + 1]) {
k++;
}
if (array[k] > temp) {
array[i] = array[k];
i = k;
} else {
break;
}
}
array[i] = temp;
} /**
* 交换元素
*
* @param arr
* @param a
* @param b
*/
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}

9 Java 堆排序的更多相关文章

  1. java堆排序实现

    代码如下: public class HeapSort { public static void heapSort(DataWrap[] data) { System.out.println(&quo ...

  2. java 堆排序的实现

    堆就是一个完全二叉树,堆要求是指 该节点大于它的两个子节点.而两个字节点大小不一定. 堆排序的最坏时间复杂度为nlog(n),平均也为nlog(n),占用空间为o(1),是一种比较排序算法. 堆排序也 ...

  3. java堆排序(大根堆)

    实现堆排序的算法思路是先创建堆,也就是从叶子节点起对每一层的孩子节点及其对应位置的父亲节点进行比较,较大的孩子节点替换较小的父亲节点,一级一级比较替换,就创建出了大根堆,小根堆反之.创建好大根堆以后, ...

  4. java堆排序

    直接贴源代码: package com.java.fmd; import java.util.Scanner; public class HeapSort { int[] arr; public st ...

  5. Hark的数据结构与算法练习之堆排序

    前言 堆排序我是看了好半天别人的博客才有了理解,然后又费了九牛二虎之力才把代码写出来,我发现我的基础真的很差劲啊……不过自己选的路一定要坚持走下去.我试着把我的理解描述出来,如有不妥之处希望大家可以指 ...

  6. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  7. 堆排序算法 java 实现

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

  8. 【算法与数据结构】冒泡、插入、归并、堆排序、快速排序的Java实现代码

    详细过程就不表了,看代码吧 import java.util.Arrays; public class Sort { static int swapTimes=0; public static voi ...

  9. java基础之:堆排序

    最近做题目饱受打击,愈发觉得打好基础的重要性,于是乎,决心把基本的排序算法还有数组操作一一实现,目的在于一方面能够得到对JAVA基础的巩固,另一面在实现的过程中发现不足. 今天所实现的堆排序(最大堆) ...

随机推荐

  1. java JDBC 连接数据库查询数据与直接使用sql的疑问

    JDBC 封装连接是好的前提: SystemAuthorizingRealm c = new SystemAuthorizingRealm(); conn = c.getConnection(); / ...

  2. HTTPS那些事 用java实现HTTPS工作原理

    HTTPS那些事 用java实现HTTPS工作原理 博客分类: java历险   今天被问到关于https原理的问题,结果由于知识掌握不牢靠,停留于表面,很多细节都无法回答清楚,于是决定把https的 ...

  3. ITK Configuring and Building in VisualStudio及hello world程序编译

    1. ITK Configuring and Building in VisualStudio With Visual Studio 2010 on Windows 7 (32-bit): Launc ...

  4. Delphi中ARC内存管理的方向

    随着即将发布的10.3版本,RAD Studio R&D和PM团队正在制作Delphi在内存管理方面的新方向. 几年前,当Embarcadero开始为Windows以外的平台构建新的Delph ...

  5. ※归并排序(merge sort)

    /** 归并排序:通常以递归的方式来实现,它反复将所处理的数组分成两半,并分别对这两半进行排序, 最后再把经过排序的数组归并在一起. */ 归并排序的伪代码实现: 将数组分为两半 对左半部分排序 对右 ...

  6. 【HDU 3068】 最长回文

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3068 [算法] Manacher算法求最长回文子串 [代码] #include<bits/s ...

  7. 68. 对Extjs中store的多种操作

    转自:https://www.cnblogs.com/exmyth/archive/2013/05/16/3082045.html 先来个声明,看着不错,贴过来的,没都测试过. Store.getCo ...

  8. BZOJ 2178 Simpson积分

    思路: 我发现能用Simpson积分水的题  好像都是裸题诶233333 //By SiriusRen #include <bits/stdc++.h> using namespace s ...

  9. 【知识总结】线性筛_杜教筛_Min25筛

    首先感谢又强又嘴又可爱脸还筋道的国家集训队(Upd: WC2019 进候选队,CTS2019 不幸 rk6 退队)神仙瓜 ( jumpmelon ) 给我讲解这三种筛法~~ 由于博主的鸽子属性,这篇博 ...

  10. MyBatis ((一对多和多对一配置)实现持久化操作 之二)

    注: 此文中的实体类还是沿用上一章的Emp和Dept两个类 还是老样子,不细说 直接上代码 01.在emp.xml中  配置和Dept的多对一的相关信息 <?xml version=" ...