一、堆
1、什么是堆?
堆是有如下特点的二叉树:
1)它是完全二叉树。即除了树的最后一层节点不需要是满的,其他的每层从左到右完全是满的。
2)它常常是数组实现的。
3)堆中的每个节点都必须满足堆的条件。
每个节点的关键字都不大于其子节点的关键字,这种堆称为小根堆。
每个节点的关键字都不小于其子节点的关键字,这种堆称为大堆根。本文采用此结构演示
综上所述,堆是一棵顺序存储的按照特定规则的完全二叉树。
数组的节点的索引为index,则:
1)它的父节点的下标为:(index-1)/2
2)它的左子节点的下表为:2*index + 1
3)它的左子节点的下表为:2*index + 2
2、堆与二叉搜索树的不同:
堆和二叉搜索树相比是弱序的。在二叉搜索树中,所有节点的关键字大于其左子树的关键字,小于其右子树的关键字。但是在堆中,每个节点都不小于其子节点,即从 根到叶子节点的每条路径都是降序排列的。
3、插入操作
1)将新增节点插入到数组最后第一个空着的单元中,数组容量加一。
2)向上筛选:与父节点比较,如果大于父节点的关键字,则与父节点交换。依次重复上述动作,直到父节点的关键字大于目标节点为止。
如上图:在11处插入新节点38,与父节点26比较,38>26,两者交换;38继续与父节点36比较,38>36,两者交换;38继续与父节点90比较,38<90,插入结束。
注意:
换位1中每次换位需要3次复制,两次换位需要6次复制;而换位2中先将目标节点暂存,父节点覆盖子节点,最后暂存的节点覆盖空余的节点,一共4次复制。
故需要在向上筛选过程中采用第二种换位操作。
具体代码如下:
4、删除操作
1)移走根节点。
2)把最后一个节点移动到根的位置上。
3)一直向下筛选这个节点,在两个孩子中找到最大值,如果小于最大值,两者交换,直到大于它的子节点小于它的父节点为止。
删除代码如下:
heapArray:90 36 17 25 26 7 1 2 3 19
========================================
90
36 17
25 26 7 1
2 3 19
========================================
heapArray:36 26 17 25 19 7 1 2 3
========================================
36
26 17
25 19 7 1
2 3
========================================
二、堆排序
对一个无序数组,堆排序的思想就是使用insert()在堆中插入全部无序的数据项,然后重复的使用remove(),直到堆内无数据。
1、向下筛选到适合的位置
从一个无序的数组建堆的过程就是反复使用trickleUp()函数N次,但是此过程可以使用trickleDown()函数N/2次即可完成。
堆中存在诸多叶子节点,这些叶子节点因为没有子节点所以没有违背堆的条件(大于子节点的关键字),因此不用对这些节点进行trickleDown()操作。可以从最后一个有子节点的节点开始依次向下筛选,进行trickleDown()操作直到根节点位置。那最后一个有子节点的节点索引是多少呢?若最后一个叶子节点的索引为index,则父节点便是最后一个有子节点的节点,索引为(index-1)/2=(currentSize-1-1)/2=currentSize/2-1。
从一个无序数组建堆的代码如下:
2、使用同一个数组
堆排序的过程需要两个大小为N的数组:初始数组和用于堆的数组。事实上堆和初始数组可以用同一个数组。当执行remove()操作后,堆内的节点数减一,数组最后的位置便空了出来,这时此位置可以存储移除的节点。
代码如下:
heapArray:9 25 40 86 74 14 44 82 68 49 55 68 11 4 51 63 79 85 1 72 29 64 95 45 38 57 77 57 92 24
========================================
9
25 40
86 74 14 44
82 68 49 55 68 11 4 51
63 79 85 1 72 29 64 95 45 38 57 77 57 92 24
========================================
heapArray:95 86 92 85 74 77 57 82 68 72 64 68 57 44 51 63 79 9 1 49 29 25 55 45 38 14 11 40 4 24
========================================
95
86 92
85 74 77 57
82 68 72 64 68 57 44 51
63 79 9 1 49 29 25 55 45 38 14 11 40 4 24
========================================
heapArray:1 4 9 11 14 24 25 29 38 40 44 45 49 51 55 57 57 63 64 68 68 72 74 77 79 82 85 86 92 95
三、效率
堆排序在最好与最快的情况下时间复杂度都是O(nlogn),空间复杂度为O(1)
堆排序是一种不稳定的排序