堆排序的时间复杂度,最好,最差,平均都是O(nlogn),空间复杂度O(1),是不稳定的排序
-
堆(或二叉堆),类似于完全二叉树,除叶子节点外,每个节点均拥有左子树和右子树,同时左子树和右子树也是堆。
- 小顶堆:父节点的值 <= 左右孩子节点的值
- 大顶堆:父节点的值 >= 左右孩子节点的值
-
堆的存储:
用一个数组存储堆就可以了,如【19, 17, 20, 18, 16, 21】
对于数组中的第 i 个节点(从0开始),有如下规律:
- 如果父节点存在,则它的父节点是 (i - 1) / 2; 比如3的父亲是(3-1)/2=1
- 如果左孩子存在,则它的左孩子是 2 * i + 1; 比如1的左孩子是2*1+1=3
- 如果右孩子存在,则右孩子是 2 * i + 2;比如1的右孩子是2*1+2=4
假设当前要排序的数组是:arr = [19, 17, 20, 18, 16, 21],下面以大顶堆为例,介绍如何构建大顶堆。
1、由于叶子节点没有左孩子和右孩子,所以不必从叶子节点开始调整堆,即不从18、16、21开始调整,直接从20开始调整,直至堆顶。 用伪代码(Java)描述如下:
- 1
- 2
- 3
- 4
2、如果当前节点 小于 左右孩子的最大值【此处假设是右孩子】,则交换当前节点的值与右孩子的值,并从右孩子开始,继续向下调整。由于20不大于21,因此交换20和21。
接下来从17开始,因为17 < 18, 所以交换17与18的值。
接下来,由于19 < 21 ,所以交换19和21,又由于19 < 20,所以需要继续交换19和20。
3、 经过上一步,就得到了一个大顶堆,接下来就是堆排序的过程
在这个大顶堆中,堆顶元素是整个堆中的最大值,取出堆顶元素,并与堆中的最后一个元素交换位置,即21与19交换,然后调整堆(21不动)。不断重复这个过程,每一次取出堆顶元素,并与最后一个元素交换位置,直至最后一个元素就是堆顶,这样就可以得到一个自上而下的递增的堆。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
堆排序完整代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
总结:
堆排序是不稳定的排序
- 在待排序的文件中,若存在多个关键字相同的记录,经过排序后,这些记录之间的相对次序保持不变,该排序方法是稳定的;反之,若相对次序变化,则排序不稳定。
堆排序的时间复杂度,最好最差平均都是O(nlogn),空间复杂度是O(n)。父节点与子节点交换时,需要使用一个中间变量,所以是O(1),当然创建堆的空间不计算在内。
所有内容来自转载