堆:本质是数组,通常从下标1开始存储元素。以二叉树的形式展现堆时,堆内每一个元素对应一个节点,并且节点n的的左子树下标为2n,右子树的下标为2n+1。
每一个节点的父节点下标为[n/2]。
小顶堆:每个结点的值都小于或等于其左右子结点的值,堆顶元素必然是最小值。小顶堆的每一个子堆都是小顶堆。
堆的两个关键操作:
percolate up 已经有一个小顶堆,在尾部插入一个元素,这个元素依次和他的父节点交换,直到小于等于其父节点。此时新堆也是一个小顶堆。
percolate down 假设已有一个堆,堆顶的两个子堆都是小顶堆。这时候依次交换堆顶元素和他的较小的子节点,直到小于等于其较小的子节点。这时新堆也是一个小顶堆。
当向一个堆插入元素时,每次都将元素放置在堆数组的末尾,然后通过percolate up将新插入的元素放置在正确的位置,使新堆仍然是一个小顶堆。
当有一个无序数组需要构建成小顶堆时,可以从其最后一个有子节点的元素开始,对每一个元素执行percolate down直到第一个元素。相当于每次都将子堆变为小顶堆,然后再将父堆变为小顶堆。
泛型学习,下面是将一个comparable的数组强转为可比较的E类型的数组的方法:
heap = (E[]) new Comparable[this.capacity + 1]
package pers.machi.dataSturcture.priorityQueue;
import pers.machi.dataSturcture.disorderArr.DisorderArr;
class PriorityQueue<E extends Comparable<E>> { //堆的元素类型为泛型E,必须继承Comparable
public static void main(String[] args) {
}
private int capacity = 0; //堆的容积,堆所能放置的最大元素个数,初始化后不可变
private int size = 0; //当前堆元素的个数
private E[] heap = null; //堆的数组
public int getCapacity() {
System.out.println("capacity: " + capacity);
return capacity;
}
// 获得堆容积
public int getSize() {
System.out.println("size: " + size);
return size;
}
// 获得当前堆元素个数
public void initialize(int capacity) {
this.capacity = capacity;
size = 0;
heap = (E[]) new Comparable[this.capacity + 1];
heap[0] = null;
}
// 初始化堆,注意如何获得泛型E的数组
public void putSentinel(E e) {
heap[0] = e;
}
// 放置哨兵,个人习惯,在数组零的位置放置E类型的最小对象
public boolean isFull() {
if (size == capacity) {
System.out.println("Priority queue is full");
return true;
} else
return false;
}
// 判断是否填满
public boolean isEmpty() {
if (size == 0) {
System.out.println("Priority queue is empty");
return true;
} else
return false;
}
// 判断是否为空
public void insert(E e) {
if (isFull())
return;
int i = ++size;
for (; heap[i / 2].compareTo(e) > 0; i /= 2)
heap[i] = heap[i / 2];
heap[i] = e;
}
// 插入元素,每次插入元素都要执行percolate up
public E deleteMin() {
if (isEmpty()) {
return null;
}
E minElement = heap[1];
E lastElement = heap[size];
heap[size--] = null;
int i;
int child;
for (i = 1; i * 2 <= size; i = child) {
child = i * 2;
if (child < size && heap[child].compareTo(heap[child + 1]) > 0)
child++;
if (lastElement.compareTo(heap[child]) > 0) {
heap[i] = heap[child];
} else {
heap[child] = lastElement;
break;
}
}
return minElement;
}
// 删除最小元素,最小元素就是第一个元素,但是删除之后,要依次把被删除元素的较小子元素填充到被删除元素的位置上去
public void printHeap() {
int i = 1, j = 1;
for (; i < capacity; i++) {
System.out.print(heap[i] + "\t");
if (i == Math.pow(2, j) - 1) {
System.out.println();
j++;
}
}
System.out.println();
}
public void buildHeap(E[] heapToBuild,int heapToBuildSize) {
int lastIndex = heapToBuildSize;
E tmp;
int j=-1;
int child=-1;
for (int i = lastIndex / 2; i > 0; i--) {
tmp = heapToBuild[i];
for (j = i; j*2 <= lastIndex; j = child) {
child = j * 2;
if ((child < lastIndex) && heapToBuild[child].compareTo(heapToBuild[child + 1]) > 0) {
child++;
}
if (tmp.compareTo(heapToBuild[child]) > 0) {
heapToBuild[j] = heapToBuild[child];
} else
break;
}
heapToBuild[j]=tmp;
}
}
// 构建堆,从下标为lastIndex/2的元素开始不断的percolate down
}