/*
堆是一棵完全二叉树,底层可以用数组实现,若根节点的index是0,那么若一个节点的index是i,它的父节点的index就是(i-1)/2,
左右子节点的index是i*2+1和i*2+2。
若是升序排列,就存储为最大堆,即任意节点都要比它的子节点要大。降序则存储为最小堆。
步骤:
1.构建最大堆,构建最大堆和每次调整最大堆都是把数组中最大元素调整到树顶
2.顶元素和最后元素交换,相当于把顶元素排除
3.调用adjust函数调整堆以还原为最大堆(此时不考虑已经排除的元素),重复步骤2,3直到结束
构建最大堆:
从最后一个非叶子节点(下标从0开始的情况下index是(n-2)/2)开始调用adjust函数,从下往上调整
*/
public class Main {
public static void main(String[] args) {
int[] data = new int[]{2,8,4,3,1,6,9,7,10,-2,65};
Main main = new Main();
main.heapSort(data);
for (int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
}
//堆排序主函数
public void heapSort(int[] data)
{
if (data == null || data.length <= 1)
return;
//记录当前heap的size
int heapSize = data.length;
//1.构建最大堆函数
//从最后一个非叶子节点开始
int index = (heapSize-2)/2;
for (int i = index; i >=0 ; i--) {
adjust(i,heapSize,data);
}
//2.交换最后元素和顶元素(相当于取出顶元素(最大)到最后)
while (heapSize > 1)
{
change(0,heapSize-1,data);
heapSize--;
//3.调整堆
adjust(0,heapSize,data);
}
}
//调整最大堆函数
public void adjust(int index,int heapSize,int[] data){
//左右子节点的index
int left = index*2+1;
int right = index*2+2;
//记录此次比较的三个节点中最大的节点的index
int biggest = index;
//判断左子节点是否存在且是否比当前最大值大
if (left < heapSize && data[left] > data[biggest])
{
biggest = left;
}
//判断右子节点是否存在且是否比当前最大值大,注意这里都是和biggest,不是index.因为是找出最大值,出错过一次
if (right < heapSize && data[right] > data[biggest])
{
biggest = right;
}
//判断最大值的index是否还是当前节点index,不是的话:交换,递归,是的话(本来就是最大或者这是个叶节点)就会返回
if (biggest != index)
{
change(index,biggest,data);
adjust(biggest,heapSize,data);
}
}
//交换函数
public void change(int index1,int index2,int[] data)
{
int temp = data[index1];
data[index1] = data[index2];
data[index2] = temp;
}
}