堆的性质:
(1)性质:完全二叉树或者是近似完全二叉树;
(2)分类:大顶堆:父节点不小于子节点键值,小顶堆:父节点不大于子节点键值;图展示一个最小堆:
(3)左右孩子:没有大小的顺序。
(4)堆的存储
一般都用数组来存储堆,i结点的父结点下标就为(i–1)/2。它的左右子结点下标分别为 2∗i+1 和 2∗i+2。如第0个结点左右子结点下标分别为1和2。
(5)堆的操作
建立:
以最小堆为例,如果以数组存储元素时,一个数组具有对应的树表示形式,但树并不满足堆的条件,需要重新排列元素,可以建立“堆化”的树。
插入:
将一个新元素插入到表尾,即数组末尾时,如果新构成的二叉树不满足堆的性质,需要重新排列元素,下图演示了插入15时,堆的调整。
删除:
堆排序中,删除一个元素总是发生在堆顶,因为堆顶的元素是最小的(小顶堆中)。表中最后一个元素用来填补空缺位置,结果树被更新以满足堆条件。
稳定性:不稳定排序。
插入代码实现:
每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中,这就类似于直接插入排序中将一个数据并入到有序区间中,这是节点“上浮”调整。不难写出插入一个新数据时堆的调整代码:
public class dadingdui {
public static void main(String[] args) {
int[] arr=new int[]{1,4,6,5,2,9,8,7};
sort(arr);
for(int i=0;i<arr.length-1;i++){
System.out.println(arr[i]);
}
}
public static void sort(int[] arr){
for(int i=(arr.length-1)/2;i>=0;i--){
Swap(arr,i,arr.length);}//做完整个这个循环才把最大的放在头
for(int i=arr.length-1;i>0;i--){//第一次交换后的操作
int temp=arr[i];
arr[i]=arr[0];
arr[0]=temp;
Swap(arr,0,i);
}
}
public static void Swap(int[]arr,int i,int len){
int temp=arr[i];
int lc=2*i+1;
while(lc<len){
int rc=lc+1; //
if(rc<len&&arr[lc]<arr[rc]){
lc=rc;
}
if(temp>=arr[lc]){
break;
}
arr[i]=arr[lc];
i=lc;
lc=2*i+1;
}
arr[i]=temp;
}
}