java堆排序_堆、堆排序及Java实现

一、堆

1、什么是堆?

堆是有如下特点的二叉树:

1)它是完全二叉树。即除了树的最后一层节点不需要是满的,其他的每层从左到右完全是满的。

2)它常常是数组实现的。

3)堆中的每个节点都必须满足堆的条件。

每个节点的关键字都不大于其子节点的关键字,这种堆称为小根堆。

每个节点的关键字都不小于其子节点的关键字,这种堆称为大堆根。本文采用此结构演示

综上所述,堆是一棵顺序存储的按照特定规则的完全二叉树。

567210ead54e459b315957ed737ae748.png

数组的节点的索引为index,则:

1)它的父节点的下标为:(index-1)/2

2)它的左子节点的下表为:2*index + 1

3)它的左子节点的下表为:2*index + 2

2、堆与二叉搜索树的不同:

堆和二叉搜索树相比是弱序的。在二叉搜索树中,所有节点的关键字大于其左子树的关键字,小于其右子树的关键字。但是在堆中,每个节点都不小于其子节点,即从 根到叶子节点的每条路径都是降序排列的。

3、插入操作

1)将新增节点插入到数组最后第一个空着的单元中,数组容量加一。

2)向上筛选:与父节点比较,如果大于父节点的关键字,则与父节点交换。依次重复上述动作,直到父节点的关键字大于目标节点为止。

7abe50700f4d352c28cf19f88254845f.png

a355f778adb3f9e4051822fa5786e9c8.png

670ca120464b0702b5e757b7c5409f4c.png

如上图:在11处插入新节点38,与父节点26比较,38>26,两者交换;38继续与父节点36比较,38>36,两者交换;38继续与父节点90比较,38<90,插入结束。

注意:

3a170dda42f35a13028811a9cbe36463.png

f433de143f08056f5d641a451a18fd48.png

换位1中每次换位需要3次复制,两次换位需要6次复制;而换位2中先将目标节点暂存,父节点覆盖子节点,最后暂存的节点覆盖空余的节点,一共4次复制。

故需要在向上筛选过程中采用第二种换位操作。

具体代码如下:

4、删除操作

1)移走根节点。

2)把最后一个节点移动到根的位置上。

3)一直向下筛选这个节点,在两个孩子中找到最大值,如果小于最大值,两者交换,直到大于它的子节点小于它的父节点为止。

8664d8d29a7cd324419355088383c55d.png

8385a1635e99ae9f73e49ce25e32fadc.png

a94a2f61b5e11e3d852438272cd83395.png

删除代码如下:

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次即可完成。

e3d84dba5378504808c9b5869d041a22.png

堆中存在诸多叶子节点,这些叶子节点因为没有子节点所以没有违背堆的条件(大于子节点的关键字),因此不用对这些节点进行trickleDown()操作。可以从最后一个有子节点的节点开始依次向下筛选,进行trickleDown()操作直到根节点位置。那最后一个有子节点的节点索引是多少呢?若最后一个叶子节点的索引为index,则父节点便是最后一个有子节点的节点,索引为(index-1)/2=(currentSize-1-1)/2=currentSize/2-1。

从一个无序数组建堆的代码如下:

2、使用同一个数组

堆排序的过程需要两个大小为N的数组:初始数组和用于堆的数组。事实上堆和初始数组可以用同一个数组。当执行remove()操作后,堆内的节点数减一,数组最后的位置便空了出来,这时此位置可以存储移除的节点。

9048ce071d7c478acde5103a485002c1.png

代码如下:

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)

堆排序是一种不稳定的排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值