一:数据结构 堆的概念
1.堆
堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构。它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。
堆有两个很基本的操作:增加、删除。先来说说增加元素,假设有下面这样一个堆:
这时候,有一个元素1要添加进来,这时候应该怎么办呢?第一步,将元素添加到堆的最后一个位置:
第二步,将新加入的元素与其父结点的值进行比较,若新结点的值比其父结点的值要小(就像这个例子一样),那么,交换两个结点的值,重复第二步,直到形成一个小顶堆:
这样,一个新的小顶堆诞生了!
然后就是从堆中删除一个元素了,假设在这个新的小顶堆中,我们打算删除值为1的那个结点:
第一步,将这个1删掉,假设其结点上当前没有值:
第二步,比较该删除结点(当前是最上面的那个)的两个子结点,看谁的值小,交换其中较小值和这个空结点的值(假设是null),然后重复这一步,直到该空值到最小面一行:
第三步,就是将这个空的结点从视线中移除了,这样,删除的过程就告一段落了(好吧,这个堆又回到解放前了)!
优先队列是由一个基于堆的完全二叉树表示,存储于数组pq[1..N]中,pq[0]没有使用。在insert()中,我们将N加一并把新元素添加到数组最后,然后用swim上浮恢复堆得秩序。在DelMax()中,我们从pq[1]中得到需要返回的元素,然后将pq[N]移动到pq[1],将N减一并用sink()恢复堆的秩序。
代码:
package suanfa;
public class MaxPQ {
static int pq[]={0,13,9,8,7,6,5,4,3,2,0};
static int N=pq.length-2;
public static void insert(int m) //插入元素
{
pq[++N]=m; //放在最后
swim(N); //上浮操作
}
private static void swim(int n) {
while(n>1&&less(n/2,n))
{
exch(n/2,n);
n=n/2;
}
}
private static void sink(int n) {
while(2*n<=N) //循环条件1
{
int j=2*n;
if(j<N&&less(j,j+1)) j++; //选择子节点较大的那个
if(less(j,n)) break;//当子节点比父节点小,跳出循环
exch(n,j);//交换父子节点
n=j;
}
}
private static void delMax()
{
int max=pq[1];
exch(1, N--);//交换首尾节点
pq[N+1]=0;
sink(1);//下沉操作
}
static boolean less(int a,int b)
{
return pq[a]<pq[b];
}
static void exch(int i,int j){
int temp=pq[i];
pq[i]=pq[j];
pq[j]=temp;
}
static int max(int i,int j){
if(less(i,j))
return pq[j];
else return pq[i];
}
public static void main(String[] args) {
//MaxPQ.insert(10);
MaxPQ.delMax();
for(int i=1;i<N+1;i++)
{
System.out.print(pq[i]+",");
}
}
}