堆排序的实现原理是将,数组元素,看做是位于一棵二叉树上的节点。
通过构建大根堆,需要使用父子指针,设置,左孩子和右孩子指针。设置初始的父亲指针指向二叉树的最后一个元素,
左孩子指针的下标应该为2*parent+1,右孩子指针下标 child+1
完成构建大根堆
交换堆顶堆底元素,并做减枝操作,并重复这个动作,直到长度为1
代码如下:
public static void main(String[] args) {
int[] num={5,7,4,2,0,3,1,6};
for(int p=num.length -1; p>=0 ;p--){
//完成构建大根堆
Hasp(num,p,num.length);//父节点递减遍历
}
for (int i=num.length-1;i>0;i--){
//将大根堆的堆顶节点和堆底节点交换
int tmp=num[i];
num[i]=num[0];
num[0]=tmp;
//之后的父指针从下标为0的节点开始遍历
Hasp(num,0,i);
}
System.out.println(Arrays.toString(num));
}
public static void Hasp(int[] num,int parent,int length){
//构建大根堆
int temp=num[parent];//设置临时变量,存放父节点的值
int child=2*parent+1;
while(child<length){
//如果孩子指针的长度超出了数组长度,就不执行操作,让父指针接着遍历
int rchild=child+1;
if (num[child]<num[rchild] &&rchild<length){
//如果右孩子节点的值大于左孩子节点,让右孩子节点作为孩子节点
child++;
}
if (temp>=num[child]){//如果临时节点中的值时大于孩子节点的值的,就结束循环
break;
}
num[parent]=num[child];//将孩子节点的值给父节点
parent=child;//父节点向下遍历指向孩子节点
child=2*parent+1;
}
num[parent]=temp;//循环结束后,都需要将临时节点的值,在交给当前父指针指向的节点
}
这里有一点是需要弄清楚的,否则是无法读懂代码的,就是在父指针向下遍历孩子节点的时候,当结束遍历后,按道理来说父指针应该是指向该子树的最后一个孩子节点,但是,结束一次Hasp程序后,我们需要的是,父指针在继续递减地往前走。
在调用的时候,我们给Hasp传递的参数是p,他不是parent,在程序中,向下遍历的是父指针,但是当结束程序后,p的值还是之前的那个值,并在次基础上递减。