堆排序
堆排序的描述
二叉堆
二叉堆是一个数组,它可以被看成一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。 ----摘自《算法导论》第三版二叉堆分为:最大堆和最小堆
最大堆性质:所有结点的关键值大于等于其孩子节点的关键值(空结点除外)
最小堆性质:所有结点的关键值小于等于其孩子节点的关键值(空结点除外)
冒泡排序的分析
显然,根据最大堆或者最小堆的性质而言,数组的第一个元素(二叉树的根节点元素)就是整个数列中最大或者最小的值。取出根节点值,并且将末尾的元素移至根节点,维护二叉堆性质,继续取根节点值,直到取出全部值,就会得到一个有序数列。对于堆排序的操作时间复杂度是O(nlogn)。
堆排序升序流程:
- 输入一个数组
- 构建一个最大堆
- 取第一个元素,将末尾元素放到第一个位置上
- 维护最大堆性质
- 重复3和4步骤,直到取出全部元素
原始数组 | 41 | 26 | 59 | 53 | 21 | 97 | 31 | 58 |
---|---|---|---|---|---|---|---|---|
最大堆 | 97 | 58 | 59 | 53 | 21 | 41 | 31 | 26 |
有序结果 | 21 | 26 | 31 | 41 | 53 | 58 | 59 | 97 |
文章图片
最大堆二叉树表示 堆排序升序排序的代码
private int leftChild(int parent){
return 2 * parent + 1;
}private int rightChild(int parent){
return 2 * parent + 2;
}//维护最大堆的性质
//局部最大堆的根节点下标是sIndex,最末下标是eIndex。
//换言之,维护的是从sIndex到eIndex的结点构成的最大堆
private void maxHeapify(int[] array, int sIndex, int eIndex){
int child;
int tmp;
for (tmp = array[sIndex];
leftChild(sIndex) <= eIndex;
sIndex = child){
//确定关键值更大的孩子结点
child = leftChild(sIndex);
if (rightChild(sIndex) <= eIndex){
child = array[leftChild(sIndex)] > array[rightChild(sIndex)] ? leftChild(sIndex) : rightChild(sIndex);
}
//如果孩子结点的关键值大于父结点,上升;否则最大堆性质满足结束循环
if (tmp < array[child])
array[sIndex] = array[child];
else
break;
}
//初始的根节点关键值放在正确位置上
array[sIndex] = tmp;
}private void swapArray(int[] array, int i, int j){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}public void heapSort(int[] array){
//构造最大堆,从底层开始依次向上构建
for (int i = array.length/2;
i >= 0;
i--){
maxHeapify(array, i, array.length - 1);
}
//排序
for (int i = array.length - 1;
i > 0;
i--){
swapArray(array, 0, i);
maxHeapify(array, 0, i - 1);
}
}
推荐阅读
- 球松
- 一个选择排序算法
- 排序(归并排序)
- 【图解】9张图彻底搞懂堆排序
- c语言|一文搞懂栈(stack)、堆(heap)、单片机裸机内存管理malloc
- vue|vue 上移 下移 删除 排序
- Java积累|Java积累 - 堆和栈
- 必须掌握的八种基本排序算法
- 【排序】插入排序算法
- 排序之冒泡和选择