宝宝记性很差,需要不断的强化才能有所记忆,所以。。。记录学习~~
堆是一种有序队列,普通的队列是先进先出,而堆是最小元素(最大元素)先出;
首先,堆必须是一棵完全二叉树,完全二叉树有一些性质可以很好的利用,如:
完全树(Complete Tree):从下图中看出,在第n层深度被填满之前,不会开始填第n+1层深度,还有一定是从左往右填满。
再来一棵完全三叉树:
这样有什么好处呢?好处就是能方便地把指针省略掉,用一个简单的数组来表示一棵树,如图:
那么下面介绍二叉堆:二叉堆是一种完全二叉树,其任意子树的左右节点(如果有的话)的键值一定比根节点大,上图其实就是一个二叉堆。
你一定发觉了,最小的一个元素就是数组第一个元素,那么二叉堆这种有序队列如何入队呢?看图:
假设要在这个二叉堆里入队一个单元,键值为2,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。
那如何出队呢?也不难,看图:
出队一定是出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪。这种操作的复杂度也是Ο(logn),比Ο(n)强多了吧?
代码如下:(大致代码)
package com.luxia.datastructure;
import java.util.ArrayList;
import java.util.Comparator;
/**
* 二叉堆(最小最大堆)
* @author wangluxia
*
*/
public class BinaryHeap<E extends Comparable<?>>{
// 用数组实现
private ArrayList<E> values;
private Boolean isMinHeap;
private Comparator<E> compatator;
public BinaryHeap(ArrayList<E> values,Boolean isMinHeap,Comparator<E> comparator){
this.values=values;
this.isMinHeap=isMinHeap;
this.compatator=comparator;
}
/**
* 是否为空
* @return
*/
public Boolean isEmpty(){
return values.isEmpty();
}
/**
* 获得最大/最小的元素
* @return
*/
public E get(){
if(isEmpty()){
return null;
}else{
return values.get(0);
}
}
/**
* 比较函数
* @return
*/
public int compare(E a,E b){
if(this.compatator!=null){
// 使用自己提供的比较器进行比较
return this.compatator.compare(a, b);
}else{
@SuppressWarnings("unchecked")
Comparable<E> ca=Comparable.class.cast(a);
return ca.compareTo(b);
}
}
/**
* 最小堆
* 向上调整
* 每个元素和父元素进行比较 如果比父元素小 则替换父元素
*/
public void minUp(int index){
int tmp=index;
E element=values.get(index);
// tmp>0 则肯定存在父元素
while(tmp > 0 && this.compare(element, values.get((tmp-1)/2))<0){
int next=(tmp-1)/2;
this.values.set(tmp,values.get(next));
tmp=next;
}
this.values.set(tmp, element);
}
/**
* 最大堆向上调整
* @param index
*/
public void maxUp(int index){
int tmp=index;
E element=values.get(index);
// tmp>0 则肯定存在父元素
while(tmp > 0 && this.compare(element, values.get((tmp-1)/2))>0){
int next=(tmp-1)/2;
this.values.set(tmp,values.get(next));
tmp=next;
}
this.values.set(tmp, element);
}
/**
* 最小堆向下调整
* @param index
*/
public void minDown(int index){
int tmp=index;
E element = this.values.get(tmp);
while((tmp*2+1)<this.values.size()){
int minChild=tmp*2+1;
// 找到左右孩子的 小的那个 (如果存在右孩子时)
if((tmp*2+2)<this.values.size() && this.compare(this.values.get(minChild), this.values.get(tmp*2+2))>0){
minChild++;
}
if(this.compare(this.values.get(minChild), element)>=0){
break;
}
this.values.set(tmp, this.values.get(minChild));
tmp=minChild;
}
this.values.set(tmp, element);
}
/**
* 最大堆向下调整
* @param index
*/
public void maxDown(int index){
int tmp=index;
E element = this.values.get(tmp);
while((tmp*2+1)<this.values.size()){
int maxChild=tmp*2+1;
// 找到左右孩子的 小的那个 (如果存在右孩子时)
if((tmp*2+2)<this.values.size() && this.compare(this.values.get(maxChild), this.values.get(tmp*2+2))<0){
maxChild++;
}
if(this.compare(this.values.get(maxChild), element)<=0){
break;
}
this.values.set(tmp, this.values.get(maxChild));
tmp=maxChild;
}
this.values.set(tmp, element);
}
}