堆本质或底层是一个完全二叉树,但是它跟普通的完全二叉树有所不同,完全二叉树可以用数组来存储,借助索引之间的关系来抽象构成对应的完全二叉树,当根节点索引从0开始时,索引为i的节点,其左孩子节点的索引为2i+1,右孩子为2i+2,根节点为(i-1)/2。所以说维护或建堆本质就是通过这些索引间的关系来进行不断调整。
堆分为两类:
- 小根堆:要求每个子树的根节点都是这颗子树中最小的
- 大根堆:要求每个子树的根节点都是这颗子树中最大的
以大根堆举例:
1、堆内维护一个int型变量size,用来表示当前堆内的元素数量
2、维护一个T类型的数组[]data用于存储堆内元素
一、建堆:每次插入一个数据时,都是insertInto(nums,size+1);
然后插入后有可能破坏堆的结构,此时就需要不断向上调整
使得每棵子树都要满足根节点最大
二、修改:当对堆内的某个元素进行修改后,也有可能会破坏堆的结构,比如这课子树的根节点不再是最大(最小)的(如果还满足根节点最大的化则根本不需要进行调整),那么此时就需要不断向下(变小了)或者向上(变大了)进行调整,使得每个子树满足根节点最大
三、poll():将堆顶元素(索引为0位置上存储的数)出堆,出堆后此时可以这么做,将堆顶元素与当前堆内的最后一个元素(处于size-1位置上的元素)进行交换,然后令size-1,这样原堆顶元素就位于边界之外。然后此时因为调整了堆顶有可能导致堆结构变换,此时也可能需要不断向下调整
四、peek():堆非空的话直接return data[0];
小根堆的建堆过程及堆排序
package sort;
import java.util.Arrays;
public class MyHeapSort {
public static int peek(int[]arr){
if(arr == null||arr.length<=0){
return -1;
}
return arr[0];
}
public static int pop(int[]arr){
if(arr == null||arr.length<=0){
return -1;
}
int val = arr[0];
int size = arr.length;
swap(arr,0,--size);
while (size>0){
heapfiy(arr,0,size);
swap(arr,0,--size);
}
return val;
}
private static void swap(int[]arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private static void heapfiy(int[]arr,int idx,int size){
int leftIdx = 2*idx+1;
while(leftIdx<size){
int smallestIdx = (leftIdx+1<size)?((arr[leftIdx]<=arr[leftIdx+1])?leftIdx:leftIdx+1):leftIdx;
smallestIdx = (arr[smallestIdx]<arr[idx])?smallestIdx:idx;
if(smallestIdx==idx){
break;
}
swap(arr,idx,smallestIdx);
idx = smallestIdx;
leftIdx = 2*idx+1;
}
}
public static void upAdj(int[]arr,int idx){//每插入一个就向上调整,使得整体符合堆的结构
while (arr[idx] < arr[(idx - 1) / 2]) {
swap(arr, idx, (idx - 1) / 2);
idx = (idx - 1) / 2;
}
}
public static void heapSort(int[]arr){
if(arr == null||arr.length<2){
return;
}
//这是建堆的过程,不是进行堆排序的过程
for(int i=0;i<arr.length;i++){//模拟插入建堆向上调整,也就是每插入一个位置就向上调整
upAdj(arr,i);
}
//下面这个是堆排序的过程,每次把最小值放在队尾(交换堆头和最后一个元素),然后再对堆进行堆化(向下调整),再从其内选择一个最小的放在队尾,所以堆排序得到的是个降序的有序序列
int size = arr.length;
swap(arr,0,--size);
while (size>0){
heapfiy(arr,0,size);
swap(arr,0,--size);
}
}
public static void main(String[] args) {
int[]arr = new int[]{3,4,21,546,-12,30,23,67};
int[]arr1 = new int[]{1,2,3,4,5,6,7};
heapSort(arr1);
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
}
}