堆
堆的概念:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储
方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2)
i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆
叫做最小堆或小根堆。
堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
堆是弱序的,但二叉堆总是一个完全二叉树,可以用一个一维数组层序遍历存储二叉堆的值,这样就可以把一个弱序的二叉堆转化成一个有序的一维数组。这样就能够以O(1)的时间复杂度快速查找到堆的最大元素(大堆)或最小元素(小堆)。
堆中结点与其对应数组下标关系:
传入数组下标index(对应二叉树中的某个结点n所对应的数组下标),有效长度size(二叉树中的结点个数);
n的左孩子下标:2*index+1;
n的右孩子下标:2*index+2;
n的双亲下标:(index-1)/2;
判断n是否为叶子结点: 2*index+1>=size ->为叶子节点
根节点:index=0;
层序遍历的最后一个节点:index=size-1;
下面是关于二叉堆的一些基本操作:
交换数组中两个元素的位置
private void swap(long[]array,int i,int j){
long temp=array[i];
array[i]=array[j];
array[j]=temp;
}
下面以小堆的操作为例:
向下调整(下沉) 时间复杂度O(log n)
将要调整的结点与其左右孩子作比较,不断交换结点位置,直到二叉堆满足小堆的性质
public void adjustdown(long[]array,int size,int index){
while(2*index+1<size){
int minindex=2*index+1;
if (minindex+1<size&&array[minindex+1]<array[minindex]){
minindex++;
}
if (array[index]<=array[minindex]){return;}
swap(array,index,minindex);
index=minindex;
}
}
向上调整(上浮) 时间复杂度O(log n)
将要调整的结点与双亲作比较,不断交换结点位置,直到二叉堆满足小堆的性质
public void adjustup(long[]array,int index){
while(index!=0){
int pindex=(index-1)/2;
if (array[pindex]<=array[index]){
return;
}
swap(array,pindex,index);
index=pindex;
}
}
建堆 时间复杂度O(n)
从层序遍历的最后一个结点的双亲开始一直向前到根结点,不断做向下调整
public void createsmallHeap(long[]array,int size){
//最后一个元素的双亲的下标
int pindex=(size-2)/2;
for (int i = pindex; i >=0; i--) {
adjustdown(array,size,i);
}
}
关于大堆的一些基础操作(与小堆类似)
//(大堆)向下调整(下沉)(非递归)
//时间复杂度O(log n)
public void adjustdownlarge(long[]array,int size,int index){
while(2*index+1<size){
int maxindex=2*index+1;
if (maxindex+1<size&&array[maxindex+1]>array[maxindex]){
maxindex++;
}
if (array[index]>=array[maxindex]){return;}
swap(array,index,maxindex);
index=maxindex;
}
}
//(大堆)向上调整(上浮)(非递归)
//时间复杂度O(log n)
public void adjustuplarge(long[]array,int index){
while(index!=0){
int pindex=(index-1)/2;
if (array[pindex]>=array[index]){
return;
}
swap(array,pindex,index);
index=pindex;
}
}
//(大堆)建堆
//时间复杂度O(n)
public void createlargeHeap(long[]array,int size){
//最后一个元素的双亲的下标
int pindex=(size-2)/2;
for (int i = pindex; i >=0; i--) {
adjustdownlarge(array,size,i);
}
}