一、堆性质
n个关键字序列k1,k2,.........kn当且仅当满足一下性质是为一个堆
- k[i]<=k[2i]
- k[i]<=k[2i+1](1≤i≤ n/2)
以上是小顶堆的定义,大顶堆则相反吧<=改为大于等于即可。若将堆看成一颗二叉树,那么则树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
1、堆的构建
找到第一个非叶子节点,根据大顶堆或者小顶堆的性质进行调整,当前以及其左右子节点比较。
注意,被调整的节点,还有子节点的情况,需要递归进行调整。
注意,被调整的节点,还有子节点的情况,需要递归进行调整。
2、堆的插入
插入节点时,先插入到最后,然后再调整堆
3、堆的删除
删除最小节点即删除根节点,先将根节点和最后一个节点交换,再调整堆。
二、堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
package Sort;
/**
* Created by LemonTree on 2017/4/5.
*/
public class HeapSort {
/**
* 调整堆
* @param array 原始堆
* @param index 调整位置
* @param heapSize 堆大小
*/
public static void adjustHeap(int[] array,int index, int heapSize){
int left = 2*index+1;
int right = 2*index+2;
int largest = index;
if(left<heapSize && array[index]<array[left])
largest = left;
if(right<heapSize && array[largest]<array[right])
largest = right;
if(largest!=index) {
int temp = array[largest];
array[largest] = array[index];
array[index] = temp;
adjustHeap(array, largest, heapSize); //递归调整
}
}
/**
* 建立堆
* @param array 待建堆序列
*/
public static void buildHeap(int array[]){
for(int i=array.length/2-1;i>=0;i--){
adjustHeap(array,i,array.length); //如看成完全二叉树,那么则从树的第一个非叶子节点进行调整,顺序为array.length/2-1 ------>0,从后向前
}
}
/**
* 堆排序
* @param array 堆排序
*/
public static void sort(int[] array){
buildHeap(array);
for(int i=array.length-1;i>=0;i--){
int temp = array[0];
array[0] = array[i];
array[i] = temp;
adjustHeap(array,0,i); //每次堆的大小递减
}
}
public static void main(String[] args) {
int[] array={9,3,4,6,1,2,3,45,6};
sort(array);
for(int num:array){
System.out.print(String.valueOf(num)+" ");
}
}
}
三、应用
题目:从1亿个数中求出最大的前100个数。
思路:建立一个100元素的小顶堆,每次从剩下的数里面取插入,如果比堆顶小则不比较,如果比堆顶大则相比较调整堆。大顶堆虽然也可以,但是浪费了堆的性质,不能像小顶堆一样减少比较的次数。