【声明】
非完全原创,部分内容来自于学习其他人的理论。如果有侵权,请联系我,可以立即删除掉。
一、堆排序
1、方法和复杂度
1.1、核心思想
- 利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点
- 根据这个特点,先将待排序的序列构造成一个小顶堆,则堆顶就是序列中最小的元素
- 取出堆顶元素,用最后一个元素填充堆顶,然后重新构建小顶堆
- 重复上面过程,取出来的元素就是一个从小到大的有序序列
1.2、主要方法
1.2.1、筛选法
(1)构建小顶堆:按照完全二叉树的规则,将元素依次填充到树上的结点;然后根据下往上,从右往左得顺序,根据小顶堆的规则比较子结点和父结点进行调整,直到整棵树都满足小顶堆的要求
(2)取出堆顶元素,剩余元素重新构建小顶堆
(3)重复(2),直到序列只剩下一个元素,则取出来的序列就是有序序列
1.2.2、插入法
主要区别在于初始创建堆的过程。筛选法是先用元素依次填满二叉树,然后根据规则进行调整;而插入法:
- 假设二叉树是空的,先将第一个元素作为根结点
- 从后面取一个待插入的结点,将被插入元素与其父节点进行比较,若大于父节点,则与父节点交换交换后继续向上检查,直到根结点
- 重复上一个步骤,直到所有元素插入到完全二叉树中并调整成小顶堆
1.3、特点及构建堆的分析
(1)特点:
- 对于小顶堆有:
arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]
- 对于大顶堆有:
arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
(2)分析
注意:数组最后一个元素是一个叶子结点,因此以此为突破口,可以查找其父结点。
当完全二叉树除了叶子结点之外,其他结点均有左右子结点时,树的结点总个数为奇数,以此分析:
- 若数组长度为偶数,则最后元素是左叶子结点,得:
2*dad + 1 == len(arr)-1 ==> dad = len(arr)/2 -1
- 若数组长度为奇数,则最后元素是右叶子结点,得:
2*dad + 2 == len(arr)-1 ==> dad = [len(arr)-1] /2 - 1
因此,最后一个元素的父结点索引是len(arr)/2-1
,而该结点也是最后一个非叶子结点
1.3、稳定性
该算法不能保证相等元素的相对顺序,属于非稳定排序。原因是,父结点和子节点进行交换时,可能会将后面的元素交换到前面去,从而破坏稳定性
举例:假如数组{5, 7, 6, 4, 3, 4}
。则小顶堆构建时,第一次交换就破坏了稳定性。
1.4、时间复杂度
具体分析见:堆排序算法描述及时间复杂度分析
1.4.1、初始化堆的时间复杂度
最好情况:当按照顺序排列出的完全二叉树完全满足堆的规则时,父结点只需要和左右子结点比较大小,不需要进行元素交换,其时间复杂度为 O ( N ) O(N) O(N)
最坏情况:当每次调整堆进行检查时,父节点每次都需要和子结点交换位置,且子节点也需要不停往下检查换位,直到叶子结点。设当前结点的深度为k
,则该层的结点最多有 2 k − 1 2^{k-1} 2k−1。设堆的高度为 h = l o g 2 N h = log_2N h=log2N,则当前结点最坏情况需要移动到最后一层,则移动的次数为h - k
。而每一层需要和左、右节点比较,因此每层需要比较2
次。那么最坏情况下的时间复杂度为:
T [ N ] = T[N] = T[N]= ∑ k = 1 h − 1 2 k − 1 ∗ 2 ∗ ( h − k ) \sum_{k=1}^{h-1}2^{k-1}*2*(h-k) ∑k=1h−12k−1∗2∗(h−k)= ∑ k = 1 h − 1 2 k ( h − k ) \sum_{k=1}^{h-1}2^k(h-k) ∑k=1h−12k(h−k)
= ( h − 1 ) 2 1 + ( h − 2 ) 2 2 + ( h − 3 ) 2 3 + . . + 2 h − 1 ∗ 1 = (h-1)2^1+(h-2)2^2+(h-3)2^3+..+2^{h-1}*1 =(h−1)21+(h−2)22+(h−3)23+..+2h−1∗1
由于 2 T [ N ] = ( h − 1 ) 2 2 + ( h − 2 ) 2 3 + ( h − 3 ) 2 4 + . . + 2 h ∗ 1 2T[N]=(h-1)2^2+(h-2)2^3+(h-3)2^4+..+2^h*1 2T[N]=(h−1)22+(h−2)23+(h−3)24+..+2h∗1, 因此
T [ N ] = 2 0 + 2 1 + 2 2 + 2 3 + . . + 2 h − 2 ∗ h − 1 T[N]=2^0+2^1+2^2+2^3+..+2^h-2*h-1 T[N]=2