堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2。
堆排序最重要的是构建大顶堆,然后让大顶堆的0号元素(整个堆的最大元素)与最后一个元素交换,然后通过不断调整大顶堆,不断交换,直到数组有序。
堆排序步骤:
1,构建大顶堆。(从最后一个结点往前构建)
2,0号元素与最后一个元素交换。
3,由于交换可能破坏了大顶堆的结构,所有调整大顶堆。(从第一个结点往后调整)
4,0号元素与最后一个元素交换。
重复34过程,直到整个数组有序。
过程图解
array=[16,7,3,20,17,8]
数组对应的堆
构建大顶堆
进行第一次交换
整个堆的长度减1进行调整,因为已经排序好的元素无需再调整
再进行交换
之后继续进行调整,交换,直到数组有序
代码
/*调整大顶堆
*/
public static void adjust(int []a,int start,int end ){
int tmp=a[start];//把当前元素储存起来
for (int j=2*start+1;j<=end;j=2*j+1){//从i结点的左子结点开始,也就是2i+1处开始
if(a[j]<a[j+1]&&j+1<=end){//如果左子结点小于右子结点,k指向右子结点
j++;
}
if(a[j]>tmp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
a[start]=a[j];
start=j;
}
if(a[j]<tmp){//如果子节点小于父节点,跳出循环
break;
}
}
a[start]=tmp;//把tmp放到进行赋值给父节点的子节点位置
}
/*排序代码
*/
public static void dsort(int []a){
for(int i=(a.length-1-1)/2;i>=0;i--){
adjust(a, i,a.length-1);
}//构建第一个大顶堆;
for(int j=0;j<a.length;j++){
/*第一次交换后,此时最后一个元素已经成为最大的元素了
所以下一次调整的时候不需要调整最后一个元素
也就是每进行一次交换,堆的长度需要减1
*/
int tmp = a[0];
a[0] = a[a.length-1-j];
a[a.length-1-j] = tmp;
adjust(a, 0,a.length-1-1-j);//之后不断进行调整,交换,直到数组全部有序
}
}