1.堆的定义:堆是一颗完全二叉树,堆中存储的数据局部有序。
2.最大堆的性质:任意一个节点的值,大于等于其子节点的值,所以根据这一特性,我们知道最大堆中,根节点一定是最大的值。
3.最小堆的性质:任意一个节点的值,小于等于其子节点的值,所以根据这一特性,我们知道最小堆中,根节点一定是最小的值。
堆和BST的区别:这两者没有任何关系,BST主要是左子树一定小于右子树的节点,但是堆中,左子树的所有节点可以大于右子树的任意一个节点。可以通过排序的强度,堆只是实现了局部排序,BST实现了全局排序。
本博文采用最大堆来进行讲解。
对于建堆的过程,首先是从底层插入新的值,然后进行调整,直到符合堆的性质。这里插入一个元素的最坏情况是O(logN),插入n的元素的时间是O(NlogN).思考一下这是为什么?下面会给出答案。
建堆的java实现
package cn.edu.hust;
import java.util.ArrayList;
import static java.util.Collections.swap;
public class MaxHeap {
private ArrayList<Integer> heap;
//元素的个数
private int size;
public MaxHeap(ArrayList<Integer> heap,int size) {
this.heap = heap;
this.size=size;
buildHeap();
}
private void buildHeap()
{
for (int i=size/2-1;i>=0;i--)
{
siftdown(i);
}
}
private void siftdown(int i) {
while(!isLeaf(i))
{
int leftChild=2*i+1;
int rightChild=2*i+2;
if((rightChild<size)&&heap.get(leftChild)<heap.get(rightChild))
{
leftChild=rightChild;
}
if(heap.get(i)>=heap.get(rightChild)) return;
swap(heap,i,leftChild);
i=leftChild;
}
}
private boolean isLeaf(int i)
{
return 2*i+1>size-1;
}
public static void main(String[] args)
{
ArrayList<Integer> list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
MaxHeap heap=new MaxHeap(list,list.size());
for (int i:
list) {
System.out.print(i+" ");
}
}
}
建堆的过程是,只需要从分枝节点开始,进行和子节点的比较,然后调整堆,直到符合堆的性质。具体如下图:
那么这里的建堆效率如何呢?我们知道堆的高度为logN,由于完全二叉树的性质,最底层的节点几乎是N/2,然后是N/4,所以移动的步数是:
如果删除最大的一个值,会发生什么事情呢?
那么我们需要重新调节堆,这里可以利用上述的sfitdwon函数进行调整。调整的时间复杂度为O(logN),插入也是类似的原理。