首先要知道,堆其实就是完全二叉树。所谓完全二叉树,可以理解为,在满二叉树的基础上,可以缺少一些结点,缺少的节点只能从满二叉树的右下角开始缺少。也就相当于从从左到右从上到下开始构建的一棵二叉树,节点只能这样排列,不能跳。
那么,根据完全二叉树的特点,父节点的左孩子left=父节点 x 2+1,右孩子right=父节点 x 2+2,父节点=(孩子节点-1)/2。那么,其实完全二叉树就可以放进一个数组中,根据数组下标来表示完全二叉树之间的关系。
堆排序
大根堆就是每个父节点都比两个孩子节点大。小根堆每个父节点都比孩子节点小。
构建大根堆:
构建大根堆,就是一个个节点插入堆的过程。首先,当只有一个节点时,默认这一个节点就是大根堆。然后,依次再来一个节点时,就和父节点比较,如果比父节点大,就和父节点交换,然后,如果向上还有父节点,就依次向上比较,比上面大就交换。当父节点更大或者到根节点时,一次插入结束。
代码:
public static void heapInsert(int[] arr,int index){
while(arr[index]>arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index=(index-1)/2;
}
}
private static void swap(int[] arr,int l1,int l2) {
int temp=arr[l1];
arr[l1]=arr[l2];
arr[l2]=temp;
}
当堆中某个元素变小时,就需要向下调整堆,此时,依次和两个孩子节点比较,如果孩子节点更大,就交换,然后孩子再和孩子节点比较,直到比两个孩子都大或者到叶子节点为止。
代码:
public static void heapify(int[] arr,int index,int size){
int left=index*2+1;
int right=left+1;
while (left<size){
int large;
if(right==size){
large=left;
}else {
large=arr[left]>arr[right] ? left : right;
}
if(arr[index]<arr[large]){
swap(arr,index,large);
left=large*2+1;
right=left+1;
index=large;
}else {
return;
}
}
}
private static void swap(int[] arr,int l1,int l2) {
int temp=arr[l1];
arr[l1]=arr[l2];
arr[l2]=temp;
}
上面两步其实都是为堆排序打基础的,所谓堆排序:
一、构建大根堆
二、把最后一位和数组第一位交换,因为原本数组第一位就是大根堆的根节点,因此,此时最大值变成数组最后一位。
三、此时,原本的根节点改变了,变小了,就是上面第二步代码的情景,然后此时再依次向下调整堆,使堆再次成为大根堆,注意,这一步需要排除掉刚才交换到最后一位的最大值。 此时大根堆的范围往前缩小一位。
四、循环上面的步骤,大根堆依次缩小,直到大根堆剩一个数,此时堆排序完成。
完整的堆排序代码:
public static void heapSort(int[] arr){
if(arr==null||arr.length<2){
return;
}
//构建大根堆
for (int i = 0; i < arr.length; i++) {
heapInsert(arr,i);
}
for (int i = arr.length-1; i > 0; i--) {
swap(arr,0,i);
heapify(arr,0,i);
}
}
//构建大根堆
public static void heapInsert(int[] arr,int index){
while(arr[index]>arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index=(index-1)/2;
}
}
//从上而下调整成大根堆
public static void heapify(int[] arr,int index,int size){
int left=index*2+1;
int right=left+1;
while (left<size){
int large;
if(right==size){
large=left;
}else {
large=arr[left]>arr[right] ? left : right;
}
if(arr[index]<arr[large]){
swap(arr,index,large);
left=large*2+1;
right=left+1;
index=large;
}else {
return;
}
}
}
//交换
private static void swap(int[] arr,int l1,int l2) {
int temp=arr[l1];
arr[l1]=arr[l2];
arr[l2]=temp;
}