目录
堆的概念
堆实现了树的顺序存储
大根堆:根结点大于孩子结点,并且左右子树都是大根堆
小根堆:根结点小于孩子结点,并且左右子树都是小根堆
已知父亲节点下标:parent,左孩子下标:2*parent+1,右孩子下标:2*parent+2
已知孩子结点下标:child,父亲结点下标:(child-1)/2
向下调整
class Myheap {
int[] elem=new int[20];
int usedsize=0;
public void init(int[] array) {
for (int i = 0; i < array.length; i++) {
elem[i] = array[i];
usedsize++;
}
for (int parent = (usedsize - 2) / 2; parent >= 0; parent--) {
//得到最后一个子树的根节点
shifedown(parent, usedsize);//将每个子树进行调整
}
}
public void shifedown(int parent, int sz) {//每一棵树,调整结束的位置都是末尾
//usedsize是长度
int left = 2 * parent + 1;//左孩子下标
//左孩子下标<右孩子下标
while (left < sz) {
if (left + 1 < sz) {//右孩子存在
if (elem[left + 1] > elem[left])
left++;
}//left是左右孩子最大值的下标
if (elem[parent] < elem[left]) {//根结点转换为最大值
int tmp = elem[parent];
elem[parent] = elem[left];
elem[left] = tmp;
// 有可能调整好了,但是又破坏了子树,要继续调整子树
parent = left;
left = parent * 2 + 1;
} else
break;
}
}
}
public class Heap {
public static void main(String[] args) {
Myheap myheap=new Myheap();
int []array={8,7,0,21,87,32,18,9};
myheap.init(array);
for (int i = 0; i < myheap.usedsize ; i++) {
System.out.print(myheap.elem[i]+" ");
}
}
时间复杂度:O(N)
每一层的结点个数*每一个结点调整的高度---》 Sn = n - log₂(n + 1)
优先级队列---PriorityQueue
public static void main(String[] args) {
PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();//优先级队列
}
构造方法
也就是说:不传入大小时,默认空间11,传入大小>=1时,是传入大小
add---增加元素
使用小堆存储
扩容机制
向上调整
简单模拟实现大根堆的add方法(扩容没考虑)
调整一次:复杂度O(log2 N)
public void offer(int x) {
if (usedsize == 0) {
elem[usedsize++] = x;
} else {
elem[usedsize++] = x;//开始调整
int child = usedsize - 1;
int parent = (child - 1) / 2;
while (parent >= 0) {
if (elem[parent] < elem[child]) {
int tmp = elem[parent];
elem[parent] = elem[child];
elem[child] = tmp;
child = parent;
parent = (child - 1) / 2;
} else {
break;
}
}
}
}
poll---删除元素
删除完毕,剩下的元素仍然是小堆存储
大根堆删除的模拟实现
public void poll() {
if (usedsize == 0)
throw new RuntimeException("删除元素,优先级队列为空");
else {
elem[0] = elem[usedsize - 1];
usedsize--;
shifedown(0,usedsize);
}
}
TOPK问题
例如:给定100个无序的数字,找到前10个最大的元素
public static void main(String[] args) {
PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();
int []array={1,3,2,4,5,2,3,2,4,8,9,0,98,78,76};
int k=5;
for(int i=0;i<k;i++){
priorityQueue.add(array[i]);
}
for(int i=k;i<array.length;i++) {
if(!priorityQueue.isEmpty()) {
if (priorityQueue.peek() < array[i]) {
priorityQueue.poll();
priorityQueue.add(array[i]);
}
}
}
System.out.println(priorityQueue);
}
求前k个最大的元素:建立小根堆
求前k个最小的元素:建立大根堆
求第k个最大的元素:建立小根堆,顶点元素
求第k个最小的元素:建立大根堆,顶点元素
堆排序
从小到大排:大根堆
从大到小排:小根堆
建立小根堆,实现从大到小排
public static void shifedown(int []elem,int parent, int sz) {//每一棵树,调整结束的位置都是末尾
int left = 2 * parent + 1;//左孩子下标
//左孩子下标<右孩子下标
while (left < sz) {
if (left + 1 < sz) {//右孩子存在
if (elem[left + 1] < elem[left])
left++;
}
if (elem[parent] > elem[left]) {
int tmp = elem[parent];
elem[parent] = elem[left];
elem[left] = tmp;
// 有可能调整好了,但是又破坏了子树,要继续调整子树
parent = left;
left = parent * 2 + 1;
} else
break;
}
}
public static void main(String[] args) {
int []array={1,3,2,4,5,2,3,2,4,8,9,0,98,78,76};
for (int i = (array.length-2)/2; i >=0 ; i--) {
shifedown(array,i,array.length);
}
int end=array.length-1;
for (int i=end;i>=0;i--){
int tmp=array[0];
array[0]=array[i];
array[i]=tmp;
shifedown(array,0,i);
}
for (int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
对象的比较
class Person{
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
public class Text {
public static void main(String[] args) {
PriorityQueue<Person>priorityQueue=new PriorityQueue<>();
priorityQueue.add(new Person(30,"李四"));
priorityQueue.add(new Person(14,"王五"));
priorityQueue.add(new Person(34,"张三"));
System.out.println(priorityQueue);
}
}
抛出异常
指定小堆的比较方式
class Person{
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
class ComparatorAge implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.age-o2.age;
}
}
class ComparatorName implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
}
public class Text {
public static void main(String[] args) {
PriorityQueue<Person>priorityQueue=new PriorityQueue<>(new ComparatorName());
priorityQueue.add(new Person(30,"李四"));
priorityQueue.add(new Person(14,"王五"));
priorityQueue.add(new Person(34,"张三"));
System.out.println(priorityQueue);
}
}