- (二叉)堆实质是一个数组,可以被近似的看做一个完全二叉树。以下代码是基本的二叉树代码框架:
public class BinaryHeap<T extends Comparable<T>> { //规定其实现了Comparable接口,一是为了能对泛型进行实例化,二是保证了该类是可排序的
private int currentSize; // 堆中元素个数
private T[ ] array; //存储堆的数组,对齐索引用,array[0]不存储数
public BinaryHeap( ) { }
public BinaryHeap(T[ ] items ) {
currentSize = items.length;
array = (T[]) new Comparable[ ( currentSize + 2 ) * 11 / 10 ];
int i = 1; //数组中下标为0的地方不存放数字
for( T item : items )
array[ i++ ] = item;
buildHeap( );
}
private void buildHeap( ) {...} //建堆
private void percolateDown( int hole ) {...} //维持堆的特性
public void insert( T x ) {...} //插入元素
public T findMin( ) {...} //找到最小的元素
public T deleteMin( ) {...} //删除最小元素
public boolean isEmpty( ) {...} //判断是否为空
private void enlargeArray( int newSize ) {...} //向堆中加入元素时,可能需要对数组大小进行扩展
}
- 在完全二叉树中父结点索引为i,那么理论上左孩子索引为2i,右孩子索引为2i+1,从而能达到快速访问的目的。
- 建堆
实质上是调整数组中元素的位置,将初始的数组排好序。以下代码实现了小根堆的建立:
private void buildHeap( ) {
for( int i = currentSize / 2; i > 0; i-- ) //叶子节点不需要调整,所以从currentSize/2处开始调整
percolateDown( i );
}
private void percolateDown( int hole ) { //hole记录待调整位置
int child; //记录较小的孩子结点的下标
T tmp = array[ hole ]; //记录最开始被调整的那个数
for( ; hole * 2 <= currentSize; ) //左孩子存在,之所以循环条件为hole = child是因为经过上次调整孩子结点可能有所变动而成为需要被调整的对象
{
child = hole * 2;
if( child != currentSize && array[ child + 1 ].compareTo( array[ child ] ) < 0 ) {
//左孩子不是最后一个元素,且左孩子比右孩子大
child++;
}
if( array[ child ].compareTo( tmp ) < 0 ) { //孩子中较小的那个数比根结点小
array[ hole ] = array[ child ];
hole = child;
}
else
break;
}
array[ hole ] = tmp;
}
- 插入新元素
实质上是在数组末尾加入新元素,并通过与父结点不断比较进行上调,子结点索引为i时,父结点索引为i/2。实现代码如下:
public void insert( T x ) {
if( currentSize == array.length - 1 )
enlargeArray( array.length * 2 + 1 );
//上调过程
int hole = ++currentSize;
for( ; x.compareTo( array[ hole / 2 ] ) < 0; hole /= 2 )
array[ hole ] = array[ hole / 2 ];
array[ hole ] = x;
}
- 删除最小元素
将数组最后一个元素作为二叉树的根并进行下调。代码如下:
public T deleteMin( ) throws Exception {
if( isEmpty( ) )
throw new Exception( );
T minItem = findMin( );
array[ 1 ] = array[ currentSize-- ];
percolateDown( 1 );
return minItem;
}
- 查看堆排序结果
可以通过不断调用findMin()和deleteMin()方法达到目的。