本文已参与「新人创作礼」活动,一起开启掘金创作之路。
堆
堆只有大根堆和小根堆,而且他们都是完全二叉树
大根堆就是大的在上面
小根堆就是小的在上面
我们用数组实现堆(链表实现也是可以的)
大根堆的实现
public static class MyBigHeap{
private int[]heap;
private int size;
public MyBigHeap(int length){
heap = new int[length];
size = 0;
}
}
我们先创建我们的大根堆的类,我们在这里是数组实现的,读者要是想链表实现也不是不可以。
里面的size属性是控制堆内元素多少的。
那我们看看里面的方法
push方法
public void push(int val){
if(size == heap.length){
System.out.println("堆满了");
return;
}
heap[size] = val;
heapInsert(heap , size++);
}
private void heapInsert(int[] heap , int index){
while(heap[index] > heap[(index - 1)/2]){
swap(heap , index , (index - 1)/2);
index = (index - 1)/2;
}
}
private void swap(int[] heap , int i , int j){
int t = heap[i];
heap[i] = heap[j];
heap[j] = t;
}
上三个方法就是实现了一个压入的方法。 我们从简单的开始说
第三个方法就是简单的一个交换方法,交换数组里面的内容
第一个方法就是一个调用方法,也不是核心
第二个方法就是核心了。
我们先介绍一下参数,第一个参数是数组实现的堆 ,第二个参数就是push的位置,
(index - 1)/2 这个操作其实是找到index元素的父母。
如果自己的元素比父母大,那么就交换元素
pop方法
private void heapFy(int[] heap , int index){
int child = index * 2 + 1;
while(child < size){
if(child < size - 1 && heap[child] < heap[child + 1]){
child++;
}
if(heap[index] < heap[child]){
swap(heap , index , child);
index = child;
child = index * 2 + 1;
}else{
break;
}
}
}
public int pop(){
if(size == 0){
System.out.println("堆为空");
return -1;
}
int ret = heap[0];
swap(heap , 0 , --size);
heapFy(heap , 0);
return ret;
}
我们还是按照上面的讲解,我们先讲解最简单的,第二个函数就是一个调用函数,值得注意的是用尾巴元素去交换头元素。
这个做法可以让整个堆重新排列,并且可以做到隐形删除。其实我们知道交换之后,元素并没有被删除,只是放到了最后,然后size--
第一个方法就是让最上面的元素排到应该在的地方。
child表示的是index位置的孩子,然后在不超过允许范围内,比较两个孩子的大小,让大的孩子替代自己。
小根堆的实现
小根堆的实现其实和大根堆是一样的,只是大小位置换一下,这边就不做过多的介绍了。