其实完全二叉树只是人们脑子里抽象出来的一种数据结构,实际情况下,我们是利用数组+一个限定规则来实现二叉树的结构的。
限定规则是:下标为i的数组元素是下标为2i+1与下标为2i+2的父节点,且下标为i的数组元素的父节点的数组下标为(i-1)/2。
构建大顶堆的思路:给我一个数组arr,这个数组依次把i位置上的数加进来,让它0~i位置上的数形成大顶堆。(大致过程就是:新加入的数字与其父节点的大小进行比较,如果大于其父节点则将它与其父节点进行交换,若其父节点还有父节点,则再去与其父节点的父节点进行比较,以此类推;如果新加入的数字小于等于其父节点的值,则不做交换。)故i从0开始,依次i++,直到 i=arr.length-1。
建立大顶堆的时间复杂度:
把第i个数插入到0~i-1的数中建立大顶堆,因为前面的0到i-1个节点已经形成一个完全二叉树了,它的高度就是我的调整代价是log(i-1),同理,加入第i+1个节点建立大顶堆的调整代价就是logi。那么如果一共有N个节点,你的调整代价就是log1+log2+log3+…+log(N-1)=O(N)。
堆排序的思路:
1)先让这个数组整体变成一个大顶堆(变成大顶堆的数组并不一定会有序),然后把最后一个位置的数与堆顶位置的数做交换,堆顶位置的数一开始是数组的最大值,换完之后最大值就来到了数组最后的位置,此时让堆大小heapSize减1,最大值就永远不动了。
2)在剩下的范围中,从0开始做heapify的下沉操作重新调整成大顶堆。然后把调整好的堆顶位置的数再与现在的最后一个位置的数交换,此时,倒数第二个位置上的数就是第二大的数了。
3)每次搞定一个末尾的数,再让heapSize减1,以此类推,减完之后,整个数组就是有序的了。
public class Test{
public static void heapSort(int [] arr) {
if(arr==null||arr.length<2) {
return;
}
for(int i=0;i<arr.length;i++) {
heapInsert(arr,i);//依次将数组中i位置上的数加进来,让它0~i之间的数形成大顶堆
}
int heapSize=arr.length;//堆大小heapSize一开始等于数组的全部
swap(arr,0,--heapSize);//最后一个位置上的数与第一个位置上的数(堆顶元素)交换,堆大小减1,即最后一个位置上的数不动了
while(heapSize>0) {
heapify(arr,0,heapSize);//从0位置开始,将当前形成的堆继续调整为一个大顶堆
swap(arr,0,--heapSize);//最后一个位置上的数与第一个位置上的数(堆顶元素)交换,堆大小减1,即最后一个位置上的数不动了
}
}
//建立大顶堆的过程
public static void heapInsert(int[] arr,int index) {
while(arr[index] > arr[(index-1)/2]) {//当前index位置上的数若比其父结点上的数大,则交换他俩的位置
swap(arr,index,(index-1)/2);
index=(index-1)/2;//然后index来到了它的父节点位置,继续上面的while
}
}
//若有一个节点的值变小了,则需要往下沉(与其左右孩子中较大的数进行交换位置的)的操作
public static void heapify(int[] arr,int index,int heapSize) {
int left=index*2+1;//左孩子下标
while(left<heapSize) {//未越界,即该节点并非叶子节点,存在左孩子
//该节点有右孩子,让largest作为左右孩子较大值的下标
int largest=(left+1 < heapSize) && arr[left+1] > arr[left] ? left+1 : left;
//让largest成为该节点与该节点左右孩子中较大值的下标
largest=arr[largest] > arr[index] ? largest : index;
if(largest==index) {
break;
}
swap(arr,largest,index);//largest!=index
index=largest;//该节点下标变成了较大孩子的下标
left=index*2+1;//继续往下走,重复上面的while
}
}
public static void swap(int[] arr,int i,int j) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args) {
int[] arr= {6,3,4,3,1,3,8,5};
heapSort(arr);
for(int i:arr) {
System.out.print(i+" ");
}
}
}
输出:1 3 3 3 4 5 6 8