堆(Heap)

匿名 (未验证) 提交于 2019-12-03 00:11:01

下标关系
已知双亲(parent)的下标,则:
左孩子(left)下标 = 2 parent + 1;
右孩子(right)下标 = 2
parent + 2;
已知孩子(不区分左右)(child)下标,则:
双亲(parent)下标 = (child - 1) / 2
堆(heap)
定义:

  1. 堆逻辑上是一棵完全二叉树
  2. 堆物理上是保存在数组中
  3. 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆, 或者最大堆
  4. 反之,则是小堆,或 者小根堆,或者最小堆
  5. 堆的基本作用是,快速找集合中的最值。
    向下调整:时间复杂度:O(log(n))
    前提:左右子树必须已经是一个堆,才能调整。
    说明:
  6. array 代表存储堆的数组
  7. size 代表数组中被视为堆数据的个数
  8. index 代表要调整位置的下标
  9. left 代表 index 左孩子下标
  10. right 代表 index 右孩子下标
  11. min 代表 index 的最小值孩子的下标
    过程(以小堆为例):
  12. index 如果已经是叶子结点,则整个调整过程结束
    1. 判断 index 位置有没有孩子
    2. 因为堆是完全二叉树,没有左孩子就一定没有右孩子,所以判断是否有左孩子
    3. 因为堆的存储结构是数组,所以判断是否有左孩子即判断左孩子下标是否越界,即 left >= size 越界
  13. 确定 left 或 right,谁是 index 的最小孩子 min
    1. 如果右孩子不存在,则 min = left
    2. 否则,比较 array[left] 和 array[right] 值得大小,选择小的为 min
  14. 比较 array[index] 的值 和 array[min] 的值,如果 array[index] <= array[min],则满足堆的性质,调整结束
  15. 否则,交换 array[index] 和 array[min] 的值
  16. 然后因为 min 位置的堆的性质可能被破坏,所以把 min 视作 index,向下重复以上过程。
    //向下调整成小堆 public static void shiftDownSmall(int[]array,int size,int index){ int left=2*index+1; while(left<size){     int right=left+1;     int min=left;     while(right<size){         if(array[left]>array[right]){             min=right;         }         if(array[index]>array[min]){             swap(array,index,min);             index=min;             left=2*index+1;         }         else{             break;         }     } } } public static void swap(int array[],int i,int j){ int t=array[i]; arrat[i]=array[j]; array[j]=t;  } //向下调整成大堆 public static void shiftDownBig(int[]a,int i,int s){ while(2*i+1<s) {   int m=2*i+1;   if(m+1<s&&a[m+1]>a[m]){       m++;   }   if(a[i]>=a[m]){       break;   }   swap(a,i,m);   i=m;   }  }

向上调整

****//向上调整成小端 //直到index=0,执行循环 //找到index的双亲 //比较index和双亲的值,满足,调整结束,否则交换,然后让i=parent继续 pubic static void shiftUpSmall(int[]array,int size,int index){     while (index!=0){         int parent=(index-1)/2;         if(array[parent]<=array[index]){            break;         }         swap(array,parent,index);         index=parent;     } } ```**  **建堆**

public static void creatHeapBig(int[]array,int size){
for(int i=(s-2)/2;i>=0;i++){
shiftDownBig(a,i,s);
}
}

 **优先级队列** * 出队列:将[0]位置和[size-1]位置交换,然后做一次向下调整。 * 入队列(O(logn)):做向上调整。 * 返回队首元素:即返回[0]下标。

public class MyPriorityQueue {
// 不做扩容考虑
private int[] array;
private int size;

MyPriorityQueue() {
array = new int[16];
size = 0;
}
//入队列
public void offer(int element) {
array[size++] = element;
Heap.shiftUpSmall(array, size - 1);
}
// 出队列O(log(n))
public int poll() {
int element = array[0];
array[0] = array[--size];
Heap.shiftDownSmall(array, 0, size);
return element;
}
//取队首元素
public int peek() {
// 不做错误处理
return array[0];
}

 **TopK问题**:在海量数据中找前k大的数据             找前K个大的,建K个大小的小堆;             找前k个小的,建K个大小的大堆; **堆排序**

public static void heapSort(int[] array){
creatHeapBig(array,array.length);
for(int i=0;i<array.length-1;i++){
//无序[0,array.length-i)
//有序[array.length-i,array.length)
swap(array,i:0,j:array.length-i-1-1);
//无序[0,array.length-i-1)
//长度 array.length-i-1
shiftDownBig(array,i:0,s:array.length-i-1);
}
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!