博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
堆排序
阅读量:5113 次
发布时间:2019-06-13

本文共 1842 字,大约阅读时间需要 6 分钟。

  堆排序是采用树的形式的数据结构来进行排序的,其中每一个堆都是完全二叉树。堆排序分为大根堆与小根堆,大根堆(小根堆)表示在完全二叉树中,所用的非叶子节点都大于等于(小于等于)他们左右子节点(存在)。所以堆的顶点不是最大数就是最小数。这样的话我们就可以借助这种性质,每次都取出大根堆(小根堆)的顶点数,形成有序序列

基本步骤

首先要明白堆在数组中的表示方式。是按照从堆得顶点开始从上往下,从左往右存放到数组中

堆图

通过上面的图应该很容易理解堆在数组中的存放位置

设数组为a[0...n-1]

我们会发现非叶子节点的i的左右子节点(存在)在数组中的位置分别为i*2+1i*2+2。而在数组中最后一个非叶子节点的位置可以表示为n/2-1(n为数组的大小)。借助这些我们可以实现小根堆与大根堆的形成,同时也能实现堆排序。

  1. 首先生成小根堆或大根堆,这里以小根堆为例。我们可以将每一个非叶子节点都看做是一个最小的完全二叉树,将他们都生成小根堆,从最后一个非叶子节点开始,把其当做是根节点,逐步向前进行创建小根堆。例如上图中的大根堆,将其变成小根堆的步骤,先以30为根节点,根据小根堆的性质,需要与10互换位置;再以60为根节点,发现需要与15互换位置;最后与70为根节点,需要与原来30的位置即现在交换位置的10互换位置,最终形成小根堆。
  2. 然后就是取出形成的小根堆得顶点值,将其与堆中第N(N=n)个节点互换位置,即a[N-1]
  3. 此时小根堆被破坏,再重新生产小根堆N--,但此时要生成的数的范围为a[0...N-1]
  4. 重复上面的步骤23,直到N=1,即a[0],排序结束。

实现

不管是最开始的创建小根堆还是每次取了顶点数之后再调整成小跟堆,他们的逻辑都是一样的,即都是与其关键字的子节点进行比较选出最小值,将其放到父节点处的位置。所以调整小根堆的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 调整成最小堆
* @param arr 数组
* @param top 堆顶位置
* @param tail 堆未位置
*/
public static void fitToMinHeap(int[] arr, int top, int tail) {
int i = top;
int temp = arr[i];
int j = 2 * i + 1;//找到子节点
while (j < tail) {
if (j + 1 < tail && arr[j + 1] < arr[j])//找出左右子节点中的最小
j++;
 
if (arr[j] >= temp)//子节点都大于父节点则跳出
break;
 
arr[i] = arr[j];//将子节点向上移,即移到父节点
i = j;
j = 2 * i + 1;
}
arr[i] = temp;
}

这里的位置交换没有直接每次都进行交换,而是与前面的一样,最后才将关键字放到他所要存放的位置。

主要的生成最小堆的方法实现了,下面就是取数,再调整,再取数的循环实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void heapSort(int[] arr) {
int n = arr.length;
for (int j = n / 2 - 1; j >= 0; j--)//从最后一个非叶子节点开始,初始化生成数组表示的最小堆
fitToMinHeap(arr, j, n);
 
for (int i = n - 1; i > 0; i--) {//每次拿出堆的顶点值
//把堆中的顶点与a[i]点互换
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
fitToMinHeap(arr, 0, i);//交换后再对前i个节点进行最小堆化
}
}

当然使用小根堆进行排序后的结果是逆序序列,即从大到小的排序

总结

个人认为,堆排序要理解以下几点

  • 何为小根堆、大根堆
  • 堆的创建原理
  • 堆排序的取数原理

通过以上几点的理解就能很好的掌握堆排序。最后堆排序为不稳定排序,且时间复杂度为O(nlogn)

转载请指明出处 idisfkj博客:

转载于:https://www.cnblogs.com/Evil-Rebe/p/6011980.html

你可能感兴趣的文章
大话文本检测经典模型:EAST
查看>>
待整理
查看>>
一次动态sql查询订单数据的设计
查看>>
C# 类(10) 抽象类.
查看>>
Vue_(组件通讯)子组件向父组件传值
查看>>
jvm参数
查看>>
我对前端MVC的理解
查看>>
Silverlight实用窍门系列:19.Silverlight调用webservice上传多个文件【附带源码实例】...
查看>>
2016.3.31考试心得
查看>>
mmap和MappedByteBuffer
查看>>
Linux的基本操作
查看>>
转-求解最大连续子数组的算法
查看>>
对数器的使用
查看>>
【ASP.NET】演绎GridView基本操作事件
查看>>
ubuntu无法解析主机错误与解决的方法
查看>>
尚学堂Java面试题整理
查看>>
MySQL表的四种分区类型
查看>>
[BZOJ 3489] A simple rmq problem 【可持久化树套树】
查看>>
STM32单片机使用注意事项
查看>>
swing入门教程
查看>>