1. 程式人生 > >二叉堆的基本概念與實現

二叉堆的基本概念與實現

基本概念

二叉堆又名堆,或者優先佇列。一般實現在堆頂的元素總是最小的。
二叉堆是一顆用陣列實現的完全二叉樹。
要實現二叉堆必須滿足以下條件:
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; } }