赞
踩
由于堆是一颗完全二叉树,也就是层序遍历时数据之间不会掺杂null,因此一般用数组来存储堆
将根节点的值和他的孩子进行比较,如果是大根堆,那么如果根节点的值比孩子中的任意一节点小,那么就将根节点向下调整。由于调整的只是一部分子树,因此需要将孩子的值赋给父亲,再进行向下调整,直到父亲不再有孩子。
public void shiftDown(int parent, int len){
int child = 2 * parent + 1;
while(child < len){
if(child + 1 < usedSize && arr[child] < arr[child + 1]){
child++;//get max child
}
if(arr[child] > arr[parent]){
swap(arr,child, parent);
parent = child;
child = 2 * parent + 1;
} else {
break;
}
}
}
import java.util.Arrays; public class TestHeap { public int[] arr; public int usedSize; public TestHeap(){ arr = new int[10]; usedSize = 0; } public void initArray(int[] array){ arr = Arrays.copyOf(array,array.length); usedSize = array.length; } public void merge(){ for (int i = (usedSize - 2) / 2; i >= 0 ; i--) { shiftDown(i,usedSize); } } public void shiftDown(int parent, int len){ int child = 2 * parent + 1; while(child < len){ if(child + 1 < usedSize && arr[child] < arr[child + 1]){ child++;//get max child } if(arr[child] > arr[parent]){ swap(arr,child, parent); parent = child; child = 2 * parent + 1; } else { break; } } } public void swap(int[] arr, int i, int j){ int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } }
我们建堆的原理是从最后一个父亲节点开始,一直向下调整到根节点
设树的高度是h,那么第一层一共有2 ^ 0个节点,需要向下调整h - 1次,第二层就是2 ^ 1个节点,需要往下调整h - 2次
因此,我们通过错位相减法,可以得到建堆的时间复杂度大约是n
由于堆的建立是有一定顺序的,因此在插入元素时不能只把要插入的元素放到数组的最后一位就结束,而是要调整堆的存储的顺序。
我们使用向上调整的方法,先讲元素放到最后一位,再与其父亲进行比较,如果比父亲大就和父亲交换,然后换后再让自己作为孩子,继续和上面的父亲进行比较。直到换到根的位置处。
由于堆的优先级的存在,因此出堆的一定是位于根位置的元素。因此出堆后还需要对堆的结构进行调整。
因为如果要将整个堆重新建堆的时间复杂度较高,我们采用一种巧妙的方法——先记录堆顶元素的值,再将数组的最后一个元素放到根处,然后把根向下调整。
最后让usedSize–
由此可见,插入和删除元素的时间复杂度是logN
public void offer(int x){ if(isFull()){ arr = Arrays.copyOf(arr,arr.length * 2); arr[usedSize] = x; usedSize++; shiftUp(usedSize - 1); } } public void shiftUp(int child ){ int parent = (child - 1) / 2; while(child > 0){ if(arr[child] > arr[parent]){ swap(arr,child,parent); child = parent; parent = (child - 1) / 2; } else { break; } } } public boolean isFull(){ return usedSize == arr.length; } public int poll(){ if (isEmpty()){ return -1; } int root = arr[0]; arr[0] = arr[usedSize--]; shiftDown(0,usedSize); return root; } public boolean isEmpty(){ return usedSize == 0; }
import java.util.PriorityQueue;
构造器 | 功能介绍 |
---|---|
PriorityQueue() | 创建一个空的优先级队列,默认容量是11 |
PriorityQueue(int initialCapacity) | 创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛IllegalArgumentException异常 |
PriorityQueue(Collection<? extends E> c) | 用一个集合来创建优先级队列 |
使用实例如下:
import java.util.Comparator; import java.util.PriorityQueue; class Student implements Comparable{ int age; @Override public int compareTo(Object o) { return 0; } } class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return 0; } } public class testDemo { public static void main(String[] args) { PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); priorityQueue.offer(1); priorityQueue.offer(3); priorityQueue.offer(7); priorityQueue.offer(13); priorityQueue.offer(100); priorityQueue.offer(87); PriorityQueue<Student> studentPriorityQueue = new PriorityQueue<>(new AgeComparator()); studentPriorityQueue.offer(new Student()); studentPriorityQueue.offer(new Student()); } }
函数名 | 功能介绍 |
---|---|
boolean offer(E e) | 插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时 间复杂度 ,注意:空间不够时候会进行扩容 |
E peek() | 获取优先级最高的元素,如果优先级队列为空,返回null |
E poll() | 移除优先级最高的元素并返回,如果优先级队列为空,返回null |
int size() | 获取有效元素的个数 |
void clear() | 清空 |
boolean isEmpty() | 检测优先级队列是否为空,空返回true |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。