0
点赞
收藏
分享

微信扫一扫

堆排序及java版实现

罗蓁蓁 2022-01-21 阅读 59

堆排序

特点

  • 原地排序
  • 时间复杂度O(nlogn)

步骤

  1. 构造堆
  2. 排序

堆排序的关键就是借助“堆”这个数据结构对元素进行排序,下面简单介绍一下堆。

定义

  • 堆是一棵完全二叉树
  • 堆中每一个节点的值都必须大于等于其子树每个节点的值(大顶堆),或者是小于等于其子树每个节点的值(小顶堆)

大、小顶堆可以这样来记,顶部节点是最大的,就是大顶堆;顶部节点是最小的,就是小顶堆。

操作

在堆中插入、删除一个节点都要进行调整以满足堆的定义,这个调整的过程我们一般叫做堆化(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;
}
}
举报

相关推荐

0 条评论