堆排序及java版实现
Posted 不识君的荒漠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆排序及java版实现相关的知识,希望对你有一定的参考价值。
堆排序
特点
- 原地排序
- 时间复杂度O(nlogn)
步骤
- 构造堆
- 排序
堆排序的关键就是借助“堆”这个数据结构对元素进行排序,下面简单介绍一下堆。
堆
定义
- 堆是一棵完全二叉树
- 堆中每一个节点的值都必须大于等于其子树每个节点的值(大顶堆),或者是小于等于其子树每个节点的值(小顶堆)
大、小顶堆可以这样来记,顶部节点是最大的,就是大顶堆;顶部节点是最小的,就是小顶堆。
操作
在堆中插入、删除一个节点都要进行调整以满足堆的定义,这个调整的过程我们一般叫做堆化(heapify)。
堆化有两种:从下往上和从上往下(自底向上和自顶向下)。堆化的本质就是为了满足堆定义的特性。
插入
堆是一棵二叉树,插入元素就是在尾部插入一个叶子节点,插入之后跟它的父节点比较,是否满足定义的大小关系,如不满足就进行交换,重复这个过程。
这是从下往上的过程,以小顶堆为例就是拿某个节点和它的父节点比较,如果小于父节点就交换。
删除
每次删除的是根结点,过程是:将最后一个叶子节点和根节点交换,删除最后一个叶子节点。此时,将根节点和它的子节点比较,如果不满足定义的大小关系就交换,一直重复这个比较、交换的过程。
这个就是从上往下。
存储结构
虽然这是一个二叉树,本文采用数组作为堆的底层存储。
根节点在数组的索引为1的地方,索引0不存数据。它的左子节点索引为2*1,右子节点索引为2*1+1。
所以,对任何一个节点的索引i,它的左子节点为2*i,右子节点为2*i+1。
如果从索引0开始,则它的左子节点是2*i+1,右子节点是2*i+2,需要多加一次加法运算。
所以从索引1开始,算是一种优化,但是在实际排序的时候,待排序的数组默认是从0开始的。
排序实现
排序步骤前面说了:1、建堆,2、排序
快速实现
在java中提供的有现成的数据结构已经实现了堆这种数据结构,因此我们可以取个巧,借助这种数据结构,而不需要自己手动建堆,直接进行排序即可。
这个就是java中的优先级队列:PriorityQueue。
代码示例如下:
public class QuickHeapSort
public void sort(int[] nums)
// 默认是自然排序,也就是小顶堆,方便从小往大排序
PriorityQueue<Integer> queue = new PriorityQueue<>();
// 构造堆
for (int n : nums)
queue.offer(n);
// 排序
for (int i = 0; i < nums.length; i++)
// poll后, 内部会进行堆化,满足堆的定义
nums[i] = queue.poll();
标准实现
这里标准实现指的是不借助java提供的数据结构,自已建堆、排序,写法也比较多样,以下示例仅供参考。
public class HeapSort
public void sort(int[] nums)
// 建堆
for (int i = nums.length / 2 - 1; i >= 0; i--)
heapify(nums, i, nums.length);
// 排序,依次从当前节点堆化进行调整
for (int i = nums.length - 1; i >= 0; i--)
// 将当前堆的最大节点放到i位置
swap(nums, 0, i);
// 堆化[0,i)之前元素
heapify(nums, 0, i);
private void heapify(int[] nums, int i, int length)
// 大顶堆的节点调整
while (true)
int maxPos = i;
// 检查当前节点的值是不是小于它的左子节点
if (i * 2 + 1 < length && nums[i] < nums[i * 2 + 1])
maxPos = i * 2 + 1;
// 和i节点的右子节点也比较下,为了找出最大值的节点
if (i * 2 + 2 < length && nums[maxPos] < nums[i * 2 + 2])
maxPos = i * 2 + 2;
if (maxPos == i)
// 说明已经找不到比当前节点大的了
break;
// 交换两个节点
swap(nums, i, maxPos);
// 继续往下处理这个过程
i = maxPos;
private void swap(int[] nums, int i, int j)
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
以上是关于堆排序及java版实现的主要内容,如果未能解决你的问题,请参考以下文章