走进数据结构之排序(六)---堆排序
来源:互联网 发布:unity3d 导入 box 编辑:程序博客网 时间:2024/06/07 11:36
一、堆排序算法分析
堆排序分为两个阶段:
1、将一个数据序列建成最小/大堆,则根结点值最小/大
2、进行选择排序,每趟将最小值(根结点值)交换到后面,再将其余值调整成堆,依此重复,直到子序列长度为1,排序完成。使用最小/大堆,得到排序的结果是降/升序的。
二、代码实现
package top.einino.selectsort;
public class HeapSort {
//交换keys[i]与keys[j]元素,i、j范围由调用者控制
private static void swap(int[] keys, int i, int j){
int temp = keys[j];
keys[j] = keys[i];
keys[i] = temp;
}
//堆排序,当minheap为true时,创建最小堆,降序排序,否则创建最大堆,升序排序
public static void heapSort(int[] keys){
heapSort(keys, true);
}
private static void heapSort(int[] keys, boolean minheap) {
//创建最小/大堆,根结点最小/大
for(int i=keys.length/2-1; i>=0; i--){
sift(keys, i, keys.length-1, minheap);
}
//每趟将最小/大值交换到后而,再调整成最小/大堆
for(int i=keys.length-1; i>0; i--){
//交换key[0]与keys[i]
swap(keys, 0, i);
sift(keys, 0, i-1, minheap);
}
}
//将keys数组中以parent为根的子树调整成最小/大堆,子序列范围为parent~end
//私有方法,只被 堆排序方法调用,确保parent,end在范围内
private static void sift(int[] keys, int parent, int end, boolean minheap) {
System.out.print("sift "+ parent + ".." + end + " ");
//child是parent的左孩子
int child = 2 * parent + 1;
int value = keys[parent];
//沿较小/大值孩子结点向下筛选
while(child <= end){
if(child<end && (minheap?keys[child]>keys[child+1]:keys[child]<keys[child+1])){
//记住孩子值较小/大值
child++;
}
//若父母结点值较小/较大者
if(minheap?value>keys[child]:value<keys[child]){
//将较小/大孩子结点值上移
keys[parent] = keys[child];
//parent、child两者都向下一层
parent = child;
child = 2 * parent + 1;
}else{
break;
}
}
//当前子树的原根值调整的位置
keys[parent] = value;
print(keys);
}
//输出排序数组
private static void print(int[] keys) {
for(int key : keys){
System.out.print(key+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] keys = {81, 49, 19, 38, 76, 13, 19};
//测试降序(最小堆)
//heapSort(keys);
//测试升序(最大堆)
int[] keys2 = {81, 49, 19, 38, 76, 13, 19};
heapSort(keys2, false);
}
}
三、形象的小例子
体育老师就是尽职!又来排队了!
初始队列:A学生181,B学生149,C学生119,D学生138,E学生197,F学生176,G学生113、H学生119
老师开始创建最小堆(降序)
自己在草稿纸上依顺序将学生画成完成二叉树,然后按0~n进行从上往下、从左往右进行给学生标个号码牌,然后老师根据n/2-1=3进行对D学生的两个孩子结点进行比较,但从图可以看到D学生的孩子结点只有H学生,所以就将H学生与D学生进行比较,结果D>H,所以就将H学生移到D学生的位置,并将D学生放到H学生的位置,再计算D学生在原来H学生的位置的两个孩子结点,很明显没有孩子结点,即不再对D学生进行操作了
现在从上往下、从左往右的排序是:A学生181,B学生149,C学生119,H学生119、E学生197,F学生176,G学生113、D学生138
再进行对C学生(从D学生往左依次操作),对C学生的两个孩子结点(F、G)进行比较,结果F>G,所以进行C学生与F、G中的较小值进行比较,也就是C与G的比较,结果C>G,所以将G排到C的位置,很明显G原来的位置没有孩子结点了,所以将C直接排到G原来的位置
现在从上往下、从左往右的排序是:A学生181,B学生149,G学生113,H学生119、E学生197,F学生176,C学生119 、D学生138
再进行对B学生操作,对B学生的两个孩子结点(H、E)进行比较,结果H<E,所以进行B与H比较,结果B>H,所以将H排到B的位置,再进行H原来位置的两个孩子结点的比较,很明显只有D,所以直接进行B与D的比较,结果B>D,所以将D排到H原来的位置上,而且D原来的位置没有孩子结点了,所以就把B排到D原来的位置
现在的排序是A学生181,H学生119,G学生113,D学生138、E学生197,F学生176,C学生119 、B学生149
再进行对A学生操作,进行A学生的两个孩子结点(H、G)的比较,结果H>G,所以就进行A与G的比较,结果A>G,所以将G学生排到A学生的位置,再进行G原来位置的两个孩子结点(F、C)的比较,结果F>C,所以进行A与C的比较,结果C<A,所以把C排到G原来的位置,C原来的位置无孩子结点,所以就把A排到C原来的位置
此时老师创建的最小堆就大功告成了,保证了每一棵的子树的孩子结点都比父结点大,此时
排序是G学生113,H学生119,C学生119 、D学生138、E学生197,F学生176,A学生181,B学生149
接着老师要从树的根结点把一个个最矮的同学排到最后面了!
首先是将G学生拉出队伍,并将其排到最后,并把创建好的最小堆的最后一位学生B学生排到根结点,再对B学生进行上述对“A的相似操作”,进行H与C的比较,结果H=C,所以进行H与B操作,结果B>H,所以把H学生排到B的位置,进行H原来位置的两个孩子结点的比较,结果D<E,所以进行B与D的比较,结果D<B,所以将D排到H原来的位置,D原来的位置无孩子结点,所以将B放到D原来的位置,此时排序是H、D、C、B、E、F、A ,还有已经排好序的G113
现在老师将G拉出队伍,把A放到根结点,再进行同样创建最小堆的操作,对A进行操作,最后的排序是C、D、F、B、E、A,还有已经排好序的H119、G113
现在老师将C拉出队伍,把A放到根结点,再进行同样创建最小堆的操作,对A进行操作,最后的排序是D、B、F、A、E,还有已经排好序的C119、H119、G113
现在老师将D拉出队伍,把E放到根结点,再进行同样创建最小堆的操作,对E进行操作,最后的排序是B、A、F、E,还有已经排好序的D138、C119、H119、G113
现在老师将B拉出队伍,把E放到根结点,再进行同样创建最小堆的操作,对E进行操作,最后的排序是F、A、E,还有已经排好序的B149、D138、C119、H119、G113
现在老师将F拉出队伍,把E放到根结点,再进行同样创建最小堆的操作,对E进行操作,最后的排序是A、E,还有已经排好序的F176、B149、D138、C119、H119、G113
现在老师将A拉出队伍,把E放到根结点,再进行同样创建最小堆的操作,对E进行操作,最后的排序是E,还有已经排好序的A181、F176、B149、D138、C119、H119、G113
最后把E学生排到最前面即可:E197、A181、F176、B149、D138、C119、H119、G113
结束了排序!
四、堆排序的时间复杂度
将一个数据序列调整为堆的时间复杂度为O(log2(n)),因此堆排序的时间复杂度为O(n*log2(n))
五、堆排序的空间复杂度
堆排序的空间复杂度为O(1)
六、稳定性
堆排序算法是不稳定的,因为堆排序遵从的是从左到右的原则,如果完全二叉树的相同元素的排序是一个在左,一个在右,这样可能就错过比较的机会,导致相同关键字排序发出颠倒。本博文例子没有突出这一点,但大家可以自己出一道题试试,比如A81、B19、C49、D39、E49、F19,降序排序的最后结果是A81、C49、E49、D39、F19、B19,可以看到F与B的位置发生变化,所以堆排序是不稳定的!
七、小结
本博文从堆排序算法分析,升序和降序代码实现,老师排队的例子讲演,时间复杂度,空间复杂度以及稳定性介绍了堆排序的方方面面。
如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!
- 走进数据结构之排序(六)---堆排序
- 数据结构之堆排序(六)
- 数据结构与算法之六堆排序
- 数据结构之(堆排序)
- 走进数据结构之排序(一)---直接插入排序
- 走进数据结构之排序(二)---希尔排序
- 走进数据结构之排序(三)---冒泡排序
- 走进数据结构之排序(四)---快速排序
- 走进数据结构之排序(五)---直接选择排序
- 走进数据结构之排序(七)---归并排序
- 复习数据结构:排序算法(六)——堆排序
- 数据结构排序之堆排序
- 数据结构--排序之堆排序
- 数据结构之排序:堆排序
- 数据结构之堆排序
- 数据结构之堆排序
- 数据结构之堆排序
- 数据结构之堆排序
- 2017年5月6日我的博客开通了
- HPUOJ1214题
- 函数递归法求fibonacci数列中第n项的值
- 最小的k个数(Java实现)
- 喵哈哈村的冒菜店-(线段树的区间合并)
- 走进数据结构之排序(六)---堆排序
- 如何来做用户意图识别
- Java用实力带你走向人生巅峰
- 路途
- JDBC连接MySql入门
- 详解log4j2(下)
- Java 反射的破坏性
- ToggleButton、Switch、CheckBox小结
- select、date、iterator、if<s:标签>的使用