package com.sun.test;
import java.util.Arrays;
import java.util.Comparator;
public class HeapTestmin<E>{
Comparator<E> comparator;
int size;
E[] elements;
//取得堆中最大元素并删除
//最大堆最大值一定是根节点,当删除根节点时需要改变堆结构,使得当前最大值称为新的根节点
//通过对比得知,将堆中最大值删除后可将数组最后一个元素放于根节点位置,而后再将根节点与左右孩子值比较进行下沉操作
//下沉思路:将根节点与左右孩子值对比,与较大值交换,直到叶子结点或当前节点比左右孩子值都大时停止下沉操作
//将堆中最大值删除后返回删除的最大值
public E getmin(){
E e=elements[0];
this.swrap(0, size-1);
elements[--size]=null;
this.minheap(0);
return e;
}
//因数组可能出现存储满的情况,故需要扩容
private void grow(){
int oldCap=elements.length;
int newCap=oldCap+(oldCap<64?oldCap:oldCap>>1);
if(newCap>Integer.MAX_VALUE-8)
throw new IndexOutOfBoundsException("数组太大");
elements= Arrays.copyOf(elements,newCap);
}
/**
* 一 。将节点添加在扩充数组是最后一个位置
* 二。然后数组最后一个位置与父节点依次对比;
* @param temp
*/
public void add(E temp){
if(size==elements.length){
grow();
}
elements[size++]=temp;
//进行添加
this.siftadd(size-1);
};
/**
*
* @param index
*/
private void siftadd(int index) {
while(index>0&&
this.compare(elements[index], elements[parentIndex(index)])<0){
int parentIndex=this.parentIndex(index);
this.swrap(index, parentIndex);
index=parentIndex;
}
}
/**
* 构造方法创建小顶堆
* @param arr
*/
@SuppressWarnings("unchecked")
public HeapTestmin(E[] arr){
size=arr.length;
elements=(E[])new Object[size];
for(int i=0;i<size;i++){
elements[i]=arr[i];
}
for(int i=(size-1-1)/2;i>=0;i--){
this.minheap(i);
}
}
/**
* 小顶堆的点坐标与左右子节点进行比较,是否需要下沉
* 实现思路从下往上一次开始
* @param index
*/
private void minheap(int index) {
while(this.leftChildIndex(index)<size){
int left=this.leftChildIndex(index);
if(left+1<size){
//拥有双子节点 左右
if(this.compare(elements[left], elements[left+1])>0){
left++;
}
}
if(this.compare(elements[index], elements[left])<0){
break;
}
//交换
swrap(index, left);
index=left;
}
}
public void swrap(int i,int j){
E temp=elements[i];
elements[i]=elements[j];
elements[j]=temp;
}
//比较器
public int compare(E o1,E o2){
if(comparator==null)
return ((Comparable<E>)o1).compareTo(o2);
return comparator.compare(o1,o2);
}
//计算左子节点
public int leftChildIndex(int index){
return 2*index+1;
}
//计算右子节点
public int rightChildIndex(int index){
return 2*index+2;
}
public int parentIndex(int index){
return (index-1)/2;
}
@Override
public String toString() {
StringBuilder res=new StringBuilder();
for(E e:elements){
if(e!=null)
res.append(e+" ");
}
return res.toString();
}
public static void main(String[] args) {
Integer[] nums=new Integer[]{9,8,7,6,5,4,3,2,1,10};
HeapTestmin<Integer> heapTestmin=new HeapTestmin<>(nums);
System.out.println("将任意数组变为堆结构:");
System.out.println(heapTestmin);
heapTestmin.add(4);
System.out.println(heapTestmin);
System.out.println(heapTestmin.getmin());
System.out.println(heapTestmin);
}
}