二叉堆的基本概念與實現
阿新 • • 發佈:2019-02-09
基本概念
二叉堆又名堆,或者優先佇列。一般實現在堆頂的元素總是最小的。
二叉堆是一顆用陣列實現的完全二叉樹。
要實現二叉堆必須滿足以下條件:
1堆有序,二叉樹中每一個子樹的父節點不大於(大根堆)兩個子節點。
2樹的父節點的兩個子節點位置為 2k和2k+1(不使用陣列的0號索引),如果使用0號索引,兩個子節點的位置為2*k+1和2*k=2。
要實現堆有序,主要依靠上浮(swim)和下沉(snik)兩個操作。
在入隊時,將資料插入到元素序列尾部,然後將元素上浮到應有的位置。
在出隊時,將堆頂最小的元素刪除,用元素序列尾部的元素交換到堆頂,然後進行下沉操作,恢復堆有序。
實現
/**
* 二叉堆,小堆,降序
* @author yuli
*
*/
public class BinaryHeap<T extends Comparable<T>>{
private Comparable<T>[] data;
private int size;
private static final int DEFAULT_CAPACITY = 10;
public BinaryHeap() {
clean();
}
public void clean(){
size = 0;
swap(DEFAULT_CAPACITY);
}
/**
* 新增元素,並將元素上浮
* @param t
*/
public void insert(T t){
if(size+1 >= data.length){
swap(2*size +1);
}
//0號位置要空著,所以+了再放元素
data[++size] = t;
swim(size);
}
/**
* 刪除元素,並恢復堆有序
* @return
*/
public Comparable<T> delete(){
if(size < 0 ){
System.out.println("沒元素啦");
return null;
}
//獲得堆頂元素
Comparable<T> t = data[1];
//將堆頂元素替換成堆底元素
data[1] = data[size];
//移除堆底元素,順便把容器的大小-1
data[size--] = null;
//將交換來的元素下沉到合適的位置,恢復堆的有序性
sink(1);
return t;
}
/**
* 上浮元素,如果父節點大於子節點,就上浮元素
* @param k 元素的索引
*/
public void swim(int k){
//如果子元素不是頭結點,並且父節點大於子節點就交換
while(k > 1 && less(data[k],data[k/2])){
exchange(data, k, k/2);
k = k/2;
}
}
private void exchange(Comparable<T>[] t,int v,int w){
Comparable<T> temp = t[v];
t[v] = t[w];
t[w] = temp;
}
/**
* 下沉元素,如果元素的子節點大於父節點,就下沉元素
* @param k 元素的索引
*/
public void sink(int k){
while(2*k <= size ){
//獲取子節點
int j = 2*k;
//從兩個孩子中選出較小那個
if(j+1 <= size && !less(data[j],data[j+1])){
j++;
}
//如果子節點不小於父節點就不交換
if(less(data[k],data[j])){
break;
}
exchange(data, k, j);
k = j;
}
}
/**
* v是否比w小
* @param v
* @param w
* @return
*/
public boolean less (Comparable v,Comparable w){
return v.compareTo(w) < 0 ;
}
/**
* 擴容,交換元素
* @param newSize
*/
@SuppressWarnings("unchecked")
public void swap(int newSize){
if(newSize < size){
return;
}
Comparable<T>[] newItems = new Comparable[newSize];
for(int i=0;i<this.size;i++){
newItems[i+1]=data[i+1];
}
this.data = newItems;
}
}