一棵完全二叉树,并且双亲节点的值大于(小于)等于子节点的值,这样的二叉树成为大堆(小堆)。
堆在物理上是一个数组,其作用是找到一组数据中的最大值。
已知双亲下标parent:则左孩子下标:left=2parent+1;右孩子的下标:right=2parent+2
堆的用处:
1.解决优先级队列问题(如果vip值相等,无法保证先来先服务)
2.排序:
3.topK问题:在海量数据中,找到最大数量级的k个数:将k个数据建立最小堆,每来一个数据都与根(最小值)比较,如果比根大,则替换根,做向下调整,找出新堆里面的最小值作为根,如此重复。
在数组中找最大值的方法:
堆 | 遍历一次 |
---|---|
适合多次查找 | 适合只找一次 |
向下调整
前提:对于一棵完全二叉树,除了一个位置以外,其他所有位置都满足堆的性质
/*
* 1.找到要调整的节点的最小孩子节点{1.无左孩子:不用调整
* 2.无右孩子:左孩子为最小孩子
* 3.左右孩子存在,选出最小 的}
* 2.比较与根节点的大小{比根节点大:交换根节点与最小孩子的值,继续拿着最小孩子向下调整;
* 比根节点小:不用调整}
* */
//时间复杂度O(logn)
private void adjustHeap(int[] tree, int index) {
//找左孩子
int min =2* index + 1;
while (min < tree.length) {
//找右孩子,取最小的
if (min + 1 < tree.length && tree[min + 1] < tree[min]) {
min = min + 1;
}
//与根比较
if (tree[index] < tree[min]) {
return;
}
int t = tree[min];
tree[min] = tree[index];
tree[index] = t;
index = min;
min = 2 * index + 1;
}
}
建堆:
//时间复杂度O(n)
//粗略nO(logn)
public static void createHeap(int[] array){
//从最后一个非叶子节点的下标开始,一路向下调整至根位置
for(int i=(array.length-1-1)/2;i>=0;i--){
heapify(array,i);
}
}
public class CreateHeap {
private int[] array;
private int size;
public CreateHeap(int[] array, int size) {
this.array = new int[100];
for (int i = 0; i < size; i++) {
this.array[i] = array[i];
}
this.size = size;
getHeap(this.array, size);
}
private void getHeap(int[] array, int size) {
//大堆,从非叶子节点开始建
for(int i=(size-2)/2;i>=0;i--){
heaplify2(array,i);
}
}
private void heaplify(int[] array, int nowParent) {
int max = nowParent * 2 + 1;
if (max > size) {
return;
}
if (max + 1 < size && array[max + 1] > array[max]) {
max++;
}
//与根比较
if (array[nowParent] > array[max]) {
return;
}
//叶子比根大,调整
int t = array[max];
array[max] = array[nowParent];
array[nowParent] = t;
//继续向下调整
heaplify(array, max);
}
private static void heaplify2(int[] array,int index){
while (index<array.length) {
int max=index*2+1;
if(max>array.length){
break;
}
int right=index*2+2;
if(right>array.length){
break;
}
if(array[right]>array[max]){
max=right;
}
if(array[max]<array[index]){
break;
}
//做交换
int t=array[index];
array[index]=array[max];
array[max]=t;
index=max;
}
}
private int top() {
return this.array[0];
}
private int pop() {
int v = array[0];
//将最后一个节点放到根节点上,再做堆的重建
array[0] = array[this.size - 1];
size--;
getHeap(array, size);
return v;
}
public static void adjustUP(int[] tree, int size, int index) {
//建大堆
//向上和双亲比较
int parent = (index - 1) / 2;
if (parent == 0) {
return;
}
if (tree[index] <= tree[parent]) {
return;
}
//向上调整,与双亲节点做交换
int t = tree[index];
tree[index] = tree[parent];
tree[parent] = tree[index];
//终止条件:
adjustUP(tree, size, parent);
}
public static void adjustUP2(int[] tree, int size, int index) {
while (index > 0) {
int parent = (index - 1) / 2;
if (tree[index] <= tree[parent]) {
return;
}
int t = tree[index];
tree[index] = tree[parent];
tree[parent] = t;
index = parent;
}
}