目录
堆的概念
下标关系
初始条件
向下调整函数shiftDown
createHeap函数
PriorityQueue的中常用方法模拟实现
offer();
isFull()
shifUp()向上调整
offer()
poll();
isEmpty()
poll()
peek();
堆排序
topk问题
- 堆逻辑上是一棵完全二叉树;
- 堆物理上是保存在数组中;
- 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆;
- 反之,则是小堆,或者小根堆,或者最小堆;
- 堆的作用是快速找集合中的最值。
已知双亲(parent)的下标,则: 左孩子(left)下标 = 2 * parent + 1; 右孩子(right)下标 = 2 * parent + 2; 已知孩子(不区分左右)(child)下标,则: 双亲(parent)下标 = (child - 1) / 2;
public int[] elem;public int usedSize;public TestHeap(){this.elem=new int[10];}
以转换为大堆为例
/***向下调整函数的实现* parent:每个树的根节点* len:每棵树的调整结束位置 10* **/向下调整就是每次交换完之后会沿着当前这个路径向下检测
1.从最后一个子树出发
2.每颗子树都是向下调整的
如何调整为大根堆
问题:
1.如何找到最后一颗子树?
父亲节点:(child-1)/2;
此时节点:((len-1)-1)/2
2.parent--就可以遍历完每一棵子树了
3.最主要的问题就是写一个函数进行向下调整
4.每棵树的调整结束位置,如何判定?
每棵树调整的结束位置实际都是一样的len。
//此时的时间复杂度:每层的节点个数*每层向下检测的层数O(n)public void shiftDown(int parent,int len){int child=2*parent+1;//最起码是有左孩子的,至少有一个孩子while(child
elem[parent]){int temp=elem[child];elem[child]=elem[parent];elem[parent]=temp;//交换完之后需要继续向下检测parent=child;child=2*parent+1;}else if(elem[child]
public void createHeap(int [] array){for (int i = 0; i < array.length; i++) {elem[i]=array[i];usedSize++;}for (int parent = (usedSize-1-1)/2; parent >= 0; parent--) {shiftDown(parent,usedSize);}}
offer();
isFull()
public boolean isFull(){return usedSize==elem.length;}
shifUp()向上调整
public void shifUp(int child){int parent=(child-1)/2;while(child>0){if(elem[child]>elem[parent]){int temp=elem[child];elem[child]=elem[parent];elem[parent]=temp;child=parent;parent=(child-1)/2;}else {break;}parent=(child-1)/2;}}
offer()
//向上调整public void offer(int val){if(isFull()){//扩容elem= Arrays.copyOf(elem,2*elem.length);}elem[usedSize++]=val;//注意:shifUp(usedSize-1);}
poll();
/***** 关于出队列:每次保证出的是最大或者最小的元素* 交换0下标和最后一个下标的元素* 调整0下标这棵树* **/isEmpty()
public boolean isEmpty(){return usedSize==0;}
poll()
public int poll(){if(isEmpty()){throw new RuntimeException("优先级队列为空");}int tmp=elem[0];elem[0]=elem[usedSize-1];elem[usedSize-1]=tmp;usedSize--;shiftDown(0,usedSize);return tmp;}
peek();
/*** 返回队首元素* **/public int peek(){if(isEmpty()){throw new RuntimeException("优先队列为空");}return elem[0];}
/*** 堆排序* 从小到大排序* **//**** 从小到大排序:* 1.调整为大根堆* 2.0下标与最后一个未排序的元素进行交换* 3.end--* */public void heapSort(){int end=usedSize-1;while(end>0){int temp=elem[0];elem[0]=elem[end];elem[end]=temp;shiftDown(0,end);end--;}}
/*** 求数组中前k个最大元素 间一个小堆,大小是k,堆顶元素就是第k大的元素;* 求数组中前k个最小的元素 建立一个大堆,大小是k,堆顶元素就是第k小的;* *///这里求前k个最小的元素:public static int[] topK(int[] array,int k){//创建一个大小为K的大根堆//java中对象的比较PriorityQueue
maxHeap=new PriorityQueue<>(k, new Comparator () {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}});//2.遍历数组当中的元素,前k个元素放在队列当中,for (int i = 0; i < array.length; i++) {if(maxHeap.size() array[i]){//先弹出maxHeap.poll();//后存入maxHeap.offer(array[i]);}}}int[] tmp=new int[k];for (int i = 0; i < k; i++) {tmp[i]=maxHeap.poll();}return tmp;}
上一篇:【递归】8皇后问题用代码解决
下一篇: “万应灵药”的意思