完全二叉树可以用数组的方式进行存储(使用场景:堆排),且满足如下关系:左孩子下标=2父结点下标+1;右孩子下标=2父结点下标+2;
堆排的步骤:
1、构建初始堆(升序构建大顶堆;降序构造小顶堆)
2、构建大顶堆(从最后一个非叶子节点开始)
3、将堆顶元素与末尾元素进行交换,然后并调整大顶堆(从最后一个非叶子节点开始)
下面以升序排序为例:
有一个数组arr={6,8,4,1,3,2},将数组用堆排的方式按升序排序。
1)下图中最左侧的图为构建的初始堆,前三个图的步骤为构建大顶堆的过程,最右侧的图为堆顶元素与末尾元素进行交换之后的图。
2)下图前三张图步骤为调整大顶堆,最右侧的图为堆顶元素与末尾元素进行交换之后的图。
3)下图前三张图步骤为调整大顶堆,最右侧的图为堆顶元素与末尾元素进行交换之后的图。
堆排按照上述步骤就完成啦。
具体代码实现如下:
public class HeadSort {
public static void main(String[] args){
int[] arr = {6,8,4,1,3,2};
headSort(arr);
for(int i : arr){
System.out.print(i + " ");
}
}
private static void headSort(int[] arr){
//创建堆
for(int i = (arr.length - 1)/2;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//调整堆结构+交换堆顶元素与末尾元素
for(int i = arr.length-1; i>0;i--){
//将堆顶元素与末尾元素进行交换
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
//重新对堆进行调整
adjustHeap(arr,0,i);
}
}
private static void adjustHeap(int[] arr,int parent,int length){
//调整堆
int temp = arr[parent];
int lChild = 2 * parent + 1;
while(lChild<length){
//右孩子
int rChild = lChild + 1;
//如果有右孩子节点,并且右孩子节点的值大于左孩子节点,则选取右孩子节点
if(rChild <length && arr[lChild] < arr[rChild]){
lChild++;
}
//如果父节点的值已经大于孩子节点的值,则直接结束
if(temp>=arr[lChild]){
break;
}
//把孩子节点的值赋给父节点
arr[parent] = arr[lChild];
//选取孩子节点的左孩子节点,继续向下筛选
parent = lChild;
lChild = 2 * lChild + 1;
}
arr[parent] = temp;
}
}