大家好,今天小编来为大家解答漫画堆这个问题,漫画:什么是堆排序?很多人还不知道,现在让我们一起来看看吧!
在上一篇漫画中,小灰介绍了二叉堆这样一种强大的数据结构:
漫画:什么是二叉堆?(修正版)
那么,这个二叉堆怎样来使用呢?我们这一期将会详细讲述。
让我们回顾一下二叉堆和最大堆的特性:
1.二叉堆本质上是一种完全二叉树
2.最大堆的堆顶是整个堆中的最大元素
当我们删除一个最大堆的堆顶(并不是完全删除,而是替换到最后面),经过自我调节,第二大的元素就会被交换上来,成为最大堆的新堆顶。
正如上图所示,当我们删除值为10的堆顶节点,经过调节,值为9的新节点就会顶替上来;当我们删除值为9的堆顶节点,经过调节,值为8的新节点就会顶替上来.......
由于二叉堆的这个特性,我们每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么我们只要反复删除堆顶,反复调节二叉堆,所得到的集合就成为了一个有序集合,过程如下:
删除节点9,节点8成为新堆顶:
删除节点8,节点7成为新堆顶:
删除节点7,节点6成为新堆顶:
删除节点6,节点5成为新堆顶:
删除节点5,节点4成为新堆顶:
删除节点4,节点3成为新堆顶:
删除节点3,节点2成为新堆顶:
到此为止,我们原本的最大堆已经变成了一个从小到大的有序集合。之前说过二叉堆实际存储在数组当中,数组中的元素排列如下:
由此,我们可以归纳出堆排序算法的步骤:
1.把无序数组构建成二叉堆。
2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
publicclassHeapSort{
/**
*下沉调整
*@paramarray待调整的堆
*@paramparentIndex要下沉的父节点
*@paramparentIndex堆的有效大小
*/
publicstaticvoiddownAdjust(int[]array,intparentIndex,intlength){
//temp保存父节点值,用于最后的赋值
inttemp=array[parentIndex];
intchildIndex=2*parentIndex+1;
while(childIndex<length){
//如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
if(childIndex+1<length&&array[childIndex+1]>array[childIndex]){
childIndex++;
}
//如果父节点小于任何一个孩子的值,直接跳出
if(temp>=array[childIndex])
break;
//无需真正交换,单向赋值即可
array[parentIndex]=array[childIndex];
parentIndex=childIndex;
childIndex=2*childIndex+1;
}
array[parentIndex]=temp;
}
/**
*堆排序
*@paramarray待调整的堆
*/
publicstaticvoidheapSort(int[]array){
//1.把无序数组构建成二叉堆。
for(inti=(array.length-2)/
2;i>=0;i--){
downAdjust(array,i,array.length);
}
System.out.println(Arrays.toString(array));
//2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
for(inti=array.length-1;i>0;i--){
//最后一个元素和第一元素进行交换
inttemp=array[i];
array[i]=array[0];
array[0]=temp;
//下沉调整最大堆
downAdjust(array,0,i);
}
}
publicstaticvoidmain(String[]args){
int[]arr=newint[]{1,3,2,6,5,7,8,9,10,0};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
二叉堆的节点下沉调整(downAdjust方法)是堆排序算法的基础,这个调节操作本身的时间复杂度是多少呢?
假设二叉堆总共有n个元素,那么下沉调整的最坏时间复杂度就等同于二叉堆的高度,也就是O(logn)。
我们再来回顾一下堆排序算法的步骤:
1.把无序数组构建成二叉堆。
2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
第一步,把无序数组构建成二叉堆,需要进行n/2次循环。每次循环调用一次downAdjust方法,所以第一步的计算规模是n/2*logn,时间复杂度O(nlogn)。
第二步,需要进行n-1次循环。每次循环调用一次downAdjust方法,所以第二步的计算规模是(n-1)*logn,时间复杂度O(nlogn)。
两个步骤是并列关系,所以整体的时间复杂度同样是O(nlogn)。
OK,关于漫画堆和漫画:什么是堆排序?的内容到此结束了,希望对大家有所帮助。