HeapSort(堆排序):
-
堆
-
二叉树,有父节点(parent)和左孩子(left),右孩子(right)
-
堆的大小等于这个堆中有多少个元素
-
最大堆性质:parent>=children,父节点 大于等于 两个孩子
-
最小堆性质: children>=parent,父节点 小于等于 两个孩子
-
-
下标推算
-
叶节点(没有children的节点)的下标为(n/2)+1, (n/2)+2, ..., n, n为heap的大小
-
根节点(heap的起始点)的下标为1时,parent位置:i,则left位置: 2i,right位置: 2i + 1
-
根节点下标为0时,parent位置:i,则left:2i + 1, right:2i + 2
-
children位置:i,则parent位置: i / 2
-
-
优先队列
- insert(S,x)在集合S中插入x
- maximum(S)返回集合S中的最大元素
- extract-max(S)去掉并返回S中最大元素
- increase-key(S,x,k)把S中的x更新为k,k大于等于x
- 应用:计算机系统的作业调动,extract-max将所有作业中优先级最高的调出执行,调度器可以用insert随时增加新的作业。heap与应用程序的链接通过句柄(handle)
- 由于涉及到增删,Java中的array已经无法满足需求,储存元素的容器应选择其他
- Java中提供PriorityQueue类
public class heapSort {
//heap的根节点取0
//检查subscript作为parent时,堆是否符合最大堆性质
//maxHeapify将三个元素:父节点,左子节点,右子节点分为一个小堆,进行一次排查
//算法导论6.1
public static void maxHeapify(int[] array, int subscript, int heapEnd){
int left = subscript * 2 + 1;
int right = subscript * 2 + 2;
//假设父节点为最大的数字
int largest = subscript;
//检查左孩子是否大于最大的数字
if (left <= heapEnd && array[left] > array[largest]){
largest = left;
}
//检查右孩子是否大于最大的数字
if (right <= heapEnd && array[right] > array[largest]){
largest = right;
}
//若最大数字的下标不在父节点,则说明子节点有数字大于父节点,交换父子位置使最大堆性质成立
//同时递归,检查交换位置后,largest为父节点的堆是否符合最大堆性质
if (largest != subscript){
int temp = array[subscript];
array[subscript] = array[largest];
array[largest] = temp;
maxHeapify(array, largest, heapEnd);
}
}
//将无序的数组转换为符合最大堆性质的heap
//算法导论6.2
public static void buildMaxHeap(int[] array){
int length = array.length;
//叶节点(无children的node)为n/2+1, n/2+2,...,n
//此处只maxHeapify有子节点的节点,既除去叶节点外的节点
for (int i = length / 2; i >= 0; i --){
maxHeapify(array, i, length - 1);
}
}
//将最大堆性质heap转换为从小到大排列的数组
//算法导论6.4
public static void heapConvert(int[] array){
int length = array.length;
int heapEnd = length - 1;
//从堆中最大元素开始遍历,每次将最大元素和数组最后一个元素对调,然后将改变后的堆再维护成拥有最大堆性质的堆
//随后再次提出最大元素,重复
for (int i = length - 1; i >= 1; i --){
int temp = array[i];
array[i] = array[0];
array[0] = temp;
heapEnd = heapEnd - 1;
maxHeapify(array, 0, heapEnd);
}
}
}